Prepare the Workspace

knitr::opts_chunk$set(warning=FALSE, message=FALSE, error = FALSE) # rmd options
rm(list = ls()); invisible(gc()) # cleaning






Control Block

# f, f, 0.25 looks nice.
allowmigrants <- F # OPTIONS: T, F 
allowsympatry <- F # OPTIONS: T, F
minoverperc <- 0 # remove pairs that do not have thermal overlap (anagenesis)
costvar <- "ele"






Packages & Prefs

options(scipen = 999) # turn off scientific notation
'%notin%' <- Negate('%in%')
require(ggplot2) # load packages
Loading required package: ggplot2
require(GGally)
Loading required package: GGally
Registered S3 method overwritten by 'GGally':
  method from   
  +.gg   ggplot2
require(viridis)
Loading required package: viridis
Loading required package: viridisLite
require(caper)
Loading required package: caper
Loading required package: ape
Loading required package: MASS
Loading required package: mvtnorm
library(dplyr)

Attaching package: ‘dplyr’

The following object is masked from ‘package:MASS’:

    select

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
library(stringr)
library(maps)
library(ape)
library(EnvStats)

Attaching package: ‘EnvStats’

The following object is masked from ‘package:MASS’:

    boxcox

The following objects are masked from ‘package:stats’:

    predict, predict.lm

The following object is masked from ‘package:base’:

    print.default
library(forecast)
Registered S3 method overwritten by 'quantmod':
  method            from
  as.zoo.data.frame zoo 
require(nlme)
Loading required package: nlme

Attaching package: ‘nlme’

The following object is masked from ‘package:forecast’:

    getResponse

The following object is masked from ‘package:dplyr’:

    collapse
require(geodist)
Loading required package: geodist
require(letsR)
Loading required package: letsR
Loading required package: raster
Loading required package: sp

Attaching package: ‘raster’

The following object is masked from ‘package:nlme’:

    getData

The following object is masked from ‘package:EnvStats’:

    cv

The following object is masked from ‘package:dplyr’:

    select

The following objects are masked from ‘package:MASS’:

    area, select

The following objects are masked from ‘package:ape’:

    rotate, zoom
require(spdep)
Loading required package: spdep
Loading required package: spData
To access larger datasets in this package, install the spDataLarge package with: `install.packages('spDataLarge', repos='https://nowosad.github.io/drat/',
type='source')`
Loading required package: sf
Linking to GEOS 3.8.1, GDAL 3.1.4, PROJ 6.3.1
Registered S3 method overwritten by 'spdep':
  method   from
  plot.mst ape 
require(spatialreg)
Loading required package: spatialreg
Loading required package: Matrix
Registered S3 methods overwritten by 'spatialreg':
  method                   from 
  residuals.stsls          spdep
  deviance.stsls           spdep
  coef.stsls               spdep
  print.stsls              spdep
  summary.stsls            spdep
  print.summary.stsls      spdep
  residuals.gmsar          spdep
  deviance.gmsar           spdep
  coef.gmsar               spdep
  fitted.gmsar             spdep
  print.gmsar              spdep
  summary.gmsar            spdep
  print.summary.gmsar      spdep
  print.lagmess            spdep
  summary.lagmess          spdep
  print.summary.lagmess    spdep
  residuals.lagmess        spdep
  deviance.lagmess         spdep
  coef.lagmess             spdep
  fitted.lagmess           spdep
  logLik.lagmess           spdep
  fitted.SFResult          spdep
  print.SFResult           spdep
  fitted.ME_res            spdep
  print.ME_res             spdep
  print.lagImpact          spdep
  plot.lagImpact           spdep
  summary.lagImpact        spdep
  HPDinterval.lagImpact    spdep
  print.summary.lagImpact  spdep
  print.sarlm              spdep
  summary.sarlm            spdep
  residuals.sarlm          spdep
  deviance.sarlm           spdep
  coef.sarlm               spdep
  vcov.sarlm               spdep
  fitted.sarlm             spdep
  logLik.sarlm             spdep
  anova.sarlm              spdep
  predict.sarlm            spdep
  print.summary.sarlm      spdep
  print.sarlm.pred         spdep
  as.data.frame.sarlm.pred spdep
  residuals.spautolm       spdep
  deviance.spautolm        spdep
  coef.spautolm            spdep
  fitted.spautolm          spdep
  print.spautolm           spdep
  summary.spautolm         spdep
  logLik.spautolm          spdep
  print.summary.spautolm   spdep
  print.WXImpact           spdep
  summary.WXImpact         spdep
  print.summary.WXImpact   spdep
  predict.SLX              spdep

Attaching package: ‘spatialreg’

The following objects are masked from ‘package:spdep’:

    anova.sarlm, as_dgRMatrix_listw, as_dsCMatrix_I, as_dsCMatrix_IrW, as_dsTMatrix_listw, as.spam.listw, bptest.sarlm, can.be.simmed, cheb_setup, coef.gmsar,
    coef.sarlm, coef.spautolm, coef.stsls, create_WX, deviance.gmsar, deviance.sarlm, deviance.spautolm, deviance.stsls, do_ldet, eigen_pre_setup, eigen_setup,
    eigenw, errorsarlm, fitted.gmsar, fitted.ME_res, fitted.sarlm, fitted.SFResult, fitted.spautolm, get.ClusterOption, get.coresOption, get.mcOption,
    get.VerboseOption, get.ZeroPolicyOption, GMargminImage, GMerrorsar, griffith_sone, gstsls, Hausman.test, HPDinterval.lagImpact, impacts, intImpacts, Jacobian_W,
    jacobianSetup, l_max, lagmess, lagsarlm, lextrB, lextrS, lextrW, lmSLX, logLik.sarlm, logLik.spautolm, LR.sarlm, LR1.sarlm, LR1.spautolm, LU_prepermutate_setup,
    LU_setup, Matrix_J_setup, Matrix_setup, mcdet_setup, MCMCsamp, ME, mom_calc, mom_calc_int2, moments_setup, powerWeights, predict.sarlm, predict.SLX, print.gmsar,
    print.ME_res, print.sarlm, print.sarlm.pred, print.SFResult, print.spautolm, print.stsls, print.summary.gmsar, print.summary.sarlm, print.summary.spautolm,
    print.summary.stsls, residuals.gmsar, residuals.sarlm, residuals.spautolm, residuals.stsls, sacsarlm, SE_classic_setup, SE_interp_setup, SE_whichMin_setup,
    set.ClusterOption, set.coresOption, set.mcOption, set.VerboseOption, set.ZeroPolicyOption, similar.listw, spam_setup, spam_update_setup, SpatialFiltering,
    spautolm, spBreg_err, spBreg_lag, spBreg_sac, stsls, subgraph_eigenw, summary.gmsar, summary.sarlm, summary.spautolm, summary.stsls, trW, vcov.sarlm, Wald1.sarlm
require(rnaturalearth)
Loading required package: rnaturalearth
require(rnaturalearthdata)
Loading required package: rnaturalearthdata
require(rgeos)
Loading required package: rgeos
rgeos version: 0.5-5, (SVN revision 640)
 GEOS runtime version: 3.8.1-CAPI-1.13.3 
 Linking to sp version: 1.4-2 
 Polygon checking: TRUE 
require(sf)
require(rgdal)
Loading required package: rgdal
rgdal: version: 1.5-18, (SVN revision 1082)
Geospatial Data Abstraction Library extensions to R successfully loaded
Loaded GDAL runtime: GDAL 3.1.4, released 2020/10/20
Path to GDAL shared files: /Library/Frameworks/R.framework/Versions/4.0/Resources/library/sf/gdal
GDAL binary built with GEOS: TRUE 
Loaded PROJ runtime: Rel. 6.3.1, February 10th, 2020, [PJ_VERSION: 631]
Path to PROJ shared files: /Library/Frameworks/R.framework/Versions/4.0/Resources/library/rgdal/proj
Linking to sp version:1.4-4
To mute warnings of possible GDAL/OSR exportToProj4() degradation,
use options("rgdal_show_exportToProj4_warnings"="none") before loading rgdal.
require(raster)
world <- ne_coastline(scale = "medium", returnclass = "sf")
vlog <- function(x){
   log( x + abs(min( x , na.rm = T)) + 1)
}

setwd("~/Box Sync/CB_VF_Shared/Dry_Lab/Projects/JMPH/Analyze_Processed_Cluster_Outputs/Data")
The working directory was changed to /Users/boterolab1/Box Sync/CB_VF_Shared/Dry_Lab/Projects/JMPH/Analyze_Processed_Cluster_Outputs/Data inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
exclusion <- read.csv(file = "exclusion_nonsimpatric_nonmigrant.csv")
exclusion$realm1red[is.na(exclusion$realm1red)] <- "NA" # NA is north america not R's NA value. fix.
exclusion$realm2green[is.na(exclusion$realm2green)] <- "NA"






Load Main Data

# main dataframe ---------------------------------
setwd("~/Box Sync/CB_VF_Shared/Dry_Lab/Projects/JMPH/Process_Cluster_Outputs/Data")
load(file =  "Pair_Barrier_Data_FEB2021.rdata")
mydata <- mypairdata; rm(mypairdata)
rownames(mydata) <- mydata$Species.1
mydatahold <- mydata






initial masks

# migration ---
if(allowmigrants == F){
  mydata <- mydata[which(mydata$Migration == 1.0),]
}

# patry
if(allowsympatry == F){
  mydata <- mydata[which(mydata[,paste0(costvar, "_c0")] > 0 ),] # doesnt matter if you use ele, mat, vart paths here, will be same answer
}

sort

mydata$uniquePairId == exclusion$mydata.uniquePairId
  [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [31] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [61] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [91] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[121] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[151] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[181] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[211] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[241] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
x <- mydata[which(mydata$Species.1 == "Apteryx_owenii"),]
mydata <- mydata[order(match(mydata$uniquePairId,exclusion$mydata.uniquePairId)), ]
y <- mydata[which(mydata$Species.1 == "Apteryx_owenii"),]
# sum(y!=x, na.rm = T) # checks.
# head(mydata)
mydata$uniquePairId == exclusion$mydata.uniquePairId
  [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
 [37] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
 [73] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[109] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[145] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[181] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[217] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[253] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
rm(x,y)
# # Basic range maps for all pairs (no paths)
# wdPAM <- "/Users/boterolab1/Box Sync/CB_VF_Shared/Dry_Lab/Projects/JMPH/PREP/PAM/Data"
# setwd(wdPAM); load("cbPAM.rdata")
# setwd("~/Box Sync/CB_VF_Shared/Dry_Lab/Projects/JMPH/Process_Cluster_Outputs/Data")
# pdf("pairmaps2.pdf", width = 19, height = 9.25)
# for (i in 1:nrow(mydata)){
# x <- cbPAM[,c("Longitude(x)","Latitude(y)",mydata$Species.1bl[i])]
# x <- as.data.frame(x[x[,3] == 1,])
# if(ncol(x) == 1) {
#   x <- t(x)
#   colnames(x) <- c("lon", "lat", "pres")
#   x <- as.data.frame(x)
# } else {
#   colnames(x) <- c("lon", "lat", "pres")
# }
# 
# y <- cbPAM[,c("Longitude(x)","Latitude(y)",mydata$Species.2bl[i])]
# y <- as.data.frame(y[y[,3] == 1,])
# if(ncol(y) == 1) {
#   y <- t(y)
#   colnames(y) <- c("lon", "lat", "pres")
#   y <- as.data.frame(y)
# 
# } else {
#   colnames(y) <- c("lon", "lat", "pres")
# }
# z <- ggplot(world)+
#     geom_sf() +
#     geom_point(data = x, aes(y=lat, x=lon), color = "red") +
#     geom_point(data = y, aes(y=lat, x=lon), color = "green") +
#     theme_bw() +
#     ggtitle(i)
# print(z)
# }
# print(i)
# dev.off()
mydata_exclusion <- cbind(mydata, exclusion)
save(mydata_exclusion, file = "mydata_exclusion.rdata")
mydata$realm1 <- exclusion$realm1red
mydata$realm2 <- exclusion$realm2green
mydata$realm <- paste0(mydata$realm1, mydata$realm2)
table(mydata$realm)

AAAA AAIM ATAT ATIM ATPA IMAA IMAT IMIM IMNT NANA NTAA NTNA NTNT OCOC PAAT PANA PAPA 
  30    1   45    3    1    3    3   27    1    4    1    1  135    2    3    2    6 
mydata$realm[mydata$realm == "AAIM"]; mydata$realm[mydata$realm == "IMAA"] <-  "AAIM"
[1] "AAIM"
mydata$realm[mydata$realm == "ATIM"]; mydata$realm[mydata$realm == "IMAT"] <-  "ATIM"
[1] "ATIM" "ATIM" "ATIM"
mydata$realm[mydata$realm == "ATPA"]; mydata$realm[mydata$realm == "PAAT"] <-  "ATPA"
[1] "ATPA"
mydata$realm[mydata$realm == "IMNT"]; mydata$realm[mydata$realm == "NTIM"] <-  "IMNT"
[1] "IMNT"
mydata$realm[mydata$realm == "NTAA"]; mydata$realm[mydata$realm == "AANT"] <-  "NTAA"
[1] "NTAA"
mydata$realm[mydata$realm == "NTNA"]; mydata$realm[mydata$realm == "NANT"] <-  "NTNA"
[1] "NTNA"
mydata$realm[mydata$realm == "PANA"]; mydata$realm[mydata$realm == "NAPA"] <-  "PANA"
[1] "PANA" "PANA"
mydata$realm <- as.factor(mydata$realm); mydata$realm <- relevel(mydata$realm, "NTNT")

mydata$landgap <- as.logical(exclusion$island)

mydata$cosmopolitan <- as.logical(exclusion$cosmopolitan)

mydata$new.old <- as.logical(exclusion$new.old)

rm(exclusion, mydata_exclusion)

Impose masks & do calcuations

# filter cosmopolitan and new/old world species (there are relatively few after imposing previous masks.)
mydata <- mydata[which(mydata$cosmopolitan == FALSE & mydata$new.old == FALSE),]

# dependent variable: elevational barrier size ---
mydata$cost <- mydata[, paste0(costvar, "_c25")] 

# data filtering -----------------------
#  thermal overlap ---
mydata$MAT_overlap <- mydata[,paste0("MAT", "_ov_perc_smrnge")]
mydata <- mydata[mydata$MAT_overlap > minoverperc,]

# update sort order --------------------
mydata$sortorder <- seq(1:nrow(mydata))

# longitude ----------------------------
mydata$lon <- mydata[,paste0("lon_mean_pair_", costvar, "_c25")]

# latitude ----------------------------
mydata$lat <- mydata[,paste0("lat_mean_pair_", costvar, "_c25")]

# temperature breadth -----------------
mydata$tas_breadth <- mydata$tas_range # mean(mean(sp1 annual tas range -- one value per cell), mean(sp2 annual tas range -- one value per cell))

# mean annual temperature --------------
mydata$tas_position <- mydata$tas_mean # mean(mean(sp1 annual tas mean  -- one value per cell), mean(sp2 annual tas mean  -- one value per cell))

# precipitation breadth --------------- 
mydata$pcp_breadth <- mydata$pcp_range # mean(mean(sp1 annual pcp range  -- one value per cell), mean(sp2 annual pcp range  -- one value per cell))

# precipitation breadth --------------- 
mydata$pcp_position <- mydata$pcp_mean # mean(mean(sp1 annual pcp mean  -- one value per cell), mean(sp2 annual pcp mean  -- one value per cell))

# distance -----------------------------
mydata$distance <- mydata[,paste0("centroid_distance_",costvar,"_c25")]

# mountain mass ------------------------
mtns <- readOGR(dsn="~/Box Sync/CB_VF_Shared/Dry_Lab/Projects/JMPH/Other_Input_Data/GMBA", layer="GMBA Mountain Inventory_v1.2-World", verbose = FALSE)
wdPAM <- "/Users/boterolab1/Box Sync/CB_VF_Shared/Dry_Lab/Projects/JMPH/PREP/PAM/Data"
setwd(wdPAM); load("LonLat_BirdPAM_raster.rdata")
The working directory was changed to /Users/boterolab1/Box Sync/CB_VF_Shared/Dry_Lab/Projects/JMPH/PREP/PAM/Data inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
mtns <- rasterize(mtns, LonLat_BirdPAM_raster)
mtns@data@values[!is.na(mtns@data@values)] <- 1 # replace mountain IDs with simple coding. 1 for mountain...
mtns@data@values[is.na(mtns@data@values)] <- 0 # ...0 for no mountain

mydata$mtn_mass <- NA
for (i in 1:nrow(mydata)) {
  coords1<-data.frame(lon=mydata$lon[i], lat=mydata$lat[i]); coordinates(coords1)<-c("lon","lat"); crs(coords1)<-crs(LonLat_BirdPAM_raster) # get coordinates
  z <- extract(mtns, coords1, buffer = raster::pointDistance(c(0,0), c(0,8), lonlat = T))
  mydata$mtn_mass[i] <- sum(z[[1]]) / length(z[[1]])
}

raster::pointDistance(c(0,0), c(0,8), lonlat = T) # corresponds to a radius of just about 8 degrees.
[1] 884651.7
raster::pointDistance(c(75,75), c(75,(75+8)), lonlat = T) # polar circles are bigger, but not that much bigger. so should be OK.
[1] 893209.5
raster::plot(mtns)
raster::plot(world$geometry, add = T)
plotrix::draw.circle(70, 40, 8, nv = 1000, border = "hotpink", lty = 1, lwd = 1)
plotrix::draw.circle(140, -5, 8, nv = 1000, border = "hotpink", lty = 1, lwd = 1)
plotrix::draw.circle(-80, 10, 8, nv = 1000, border = "hotpink", lty = 1, lwd = 1)
plotrix::draw.circle(-70, -50, 8, nv = 1000, border = "hotpink",lty = 1, lwd = 1)


x <- ggplot(world)+
  geom_sf() +
  geom_point(data = mydata[order(mydata[, "mtn_mass"], decreasing = F),], aes(y=lat, x=lon, color = mtn_mass), alpha = 0.9) +
  ggtitle(i)+scale_color_viridis()
print(x)


# water buffering ----------------------
wtr <- read_sf("~/Box Sync/CB_VF_Shared/Dry_Lab/Projects/JMPH/Other_Input_Data/ne_50m_ocean/ne_50m_ocean.shp")
temp <- mtns
values(temp) <- 100
temp <- mask(temp, wtr)
wtr <- mtns
values(wtr) <- 0
wtr[temp == 100] <- 1; rm(temp)
plot(wtr)


mydata$wtrcells <- NA
mydata$wtrmass <- NA
for (i in 1:nrow(mydata)) {
  coords1<-data.frame(lon=mydata$lon[i], lat=mydata$lat[i]); coordinates(coords1)<-c("lon","lat"); crs(coords1)<-crs(LonLat_BirdPAM_raster) # get coordinates
  z <- extract(wtr, coords1, buffer = raster::pointDistance(c(0,0), c(0,8), lonlat = T))
  mydata$miniplot[i] <- length(z[[1]])
  mydata$wtrcells[i] <- sum(z[[1]])
  mydata$wtrmass[i] <- sum(z[[1]]) / length(z[[1]])
}
mydata$water_buffering <- mydata$wtrmass

x <- ggplot(world)+
  geom_sf() +
  geom_point(data = mydata[order(mydata[, "water_buffering"], decreasing = F),], aes(y=lat, x=lon, color = water_buffering), alpha = 0.9) +
  ggtitle(i)+scale_color_viridis()
print(x)



# dispersal ability --------------------
dispab <- read.csv("~/Box Sync/CB_VF_Shared/Dry_Lab/Projects/JMPH/Other_Input_Data/Bird Hand-Wing Index/Dataset HWI 2020-04-10.csv")
mydata$dispersal_ability <- NA
for (i in 1:nrow(mydata)){
  dispab_sp1 <- dispab$HWI[dispab$IUCN.name == mydata$Species.1bl[i]]
  dispab_sp2 <- dispab$HWI[dispab$IUCN.name == mydata$Species.2bl[i]]
  dispab_pair <- mean(c(dispab_sp1, dispab_sp2), na.rm = T)
  mydata$dispersal_ability[i] <- dispab_pair
  rm(dispab_sp1, dispab_sp2, dispab_pair)
}
mydata <- mydata[!is.nan(mydata$dispersal_ability),]

# pair age -----------------------------
mydata$pair_age <- mydata$Pair.age..MY.

# length of boundary -------------------
mydata$boundary_length <- mydata$boundary_length_ele_c25

# retain cols of interest only.
mydata <- mydata[,c("uniquePairId", "Species.1", "Species.2", "Species.1bl", "Species.2bl", "cost", "lat", "lon",
                    "tas_breadth","tas_position", "pcp_breadth","pcp_position", "mtn_mass", "water_buffering", 
                    "dispersal_ability", "pair_age", "distance", "boundary_length", "MAT_overlap", "realm",
                    "landgap")]

load phylo and prune

sum(mydata$Species.1 != tree$tip.label) # sorted (but still specify form below for safety)
[1] 0

Save freame for CB

setwd("~/Box Sync/CB_VF_Shared/Dry_Lab/Projects/JMPH/Analyze_Processed_Cluster_Outputs/Data")
The working directory was changed to /Users/boterolab1/Box Sync/CB_VF_Shared/Dry_Lab/Projects/JMPH/Analyze_Processed_Cluster_Outputs/Data inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
save(mydata, file = "ele_data_for_CB.rdata")
write.csv(mydata, file = "ele_data_for_CB.csv")

Neighbors for sptial analysis.

distm <- mydata[,c("lon", "lat")]
distm <- geodist(distm, measure = "geodesic")
rownames(distm) <- rownames(mydata)
colnames(distm) <- rownames(mydata)
basecols <- ncol(mydata)

# neightbors
coords<-cbind(mydata$lon, mydata$lat); coords<-as.matrix(coords) ; row.names(coords)<-rownames(mydata)
k1 <- knn2nb(knearneigh(coords, longlat = T))
knearneigh: identical points found
nb<- dnearneigh(coords,row.names = row.names(coords), d1=0,d2=max(unlist(nbdists(k1, coords, longlat = T))),longlat=T)

plots for transformations

for (i in c("cost", "lat", "lon","tas_breadth","tas_position","pcp_breadth","pcp_position", "mtn_mass", "dispersal_ability", "pair_age", "distance", "boundary_length", "MAT_overlap")) {
hist(mydata[, i], breaks = 50, main = i)
}

world plots

setwd("~/Box Sync/CB_VF_Shared/Dry_Lab/Projects/JMPH/Analyze_Processed_Cluster_Outputs/Data")
The working directory was changed to /Users/boterolab1/Box Sync/CB_VF_Shared/Dry_Lab/Projects/JMPH/Analyze_Processed_Cluster_Outputs/Data inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
pdf(file="variable_maps.pdf", width = 10, height = 7)
for (i in c("cost", "lat", "lon","tas_breadth","tas_position","pcp_breadth","pcp_position", "mtn_mass",  "water_buffering", "dispersal_ability", "pair_age", "distance", "boundary_length", "MAT_overlap", "realm", "landgap")) {
  if(i %in% c("cost")){
    myc <- mydata[, i]; myc <- vlog(myc)
    x <- ggplot(world)+
      geom_sf() +
      geom_point(data = mydata[order(mydata[, i], decreasing = F),], aes(y=lat, x=lon, color = myc), alpha = 0.85) +
      ggtitle(paste0("ln ",i))+
      scale_color_viridis()
    print(x)
  } else if (i %in% c("realm", "landgap")){
    x <- ggplot(world)+
      geom_sf() + 
      geom_point(data = mydata[order(mydata[, "cost"], decreasing = F),], aes(y=lat, x=lon, color = get(i)), alpha = 0.85) +
      ggtitle(paste0(i))+
      scale_color_viridis(discrete = T)
    print(x) 
  } else {
    x <- ggplot(world)+
      geom_sf() + 
      geom_point(data = mydata[order(mydata[, "cost"], decreasing = F),], aes(y=lat, x=lon, color = get(i)), alpha = 0.85) +
      ggtitle(i)+
      scale_color_viridis()
    print(x) 
  }
}
dev.off()
null device 
          1 

# vector 1 added ---
m <- gls(scale(I(vlog(cost))) ~ scale(I(vlog(tas_breadth))) + V22 + V23 + V24 + V25 + V26 + V27 + V28 + V29 + V30, correlation = corPagel(0.99, phy = tree,fixed = F, form = ~Species.1), data = mydata, method = "REML"); summary(m); cor(predict(m),scale(I(vlog(mydata$cost))))
Generalized least squares fit by REML
  Model: scale(I(vlog(cost))) ~ scale(I(vlog(tas_breadth))) + V22 + V23 +      V24 + V25 + V26 + V27 + V28 + V29 + V30 
  Data: mydata 

Correlation Structure: corPagel
 Formula: ~Species.1 
 Parameter estimate(s):
   lambda 
0.1132853 

Coefficients:

 Correlation: 
                            (Intr) s(I((_ V22    V23    V24    V25    V26    V27    V28    V29   
scale(I(vlog(tas_breadth))) -0.030                                                               
V22                          0.060 -0.016                                                        
V23                         -0.033  0.002 -0.008                                                 
V24                         -0.031  0.016 -0.012  0.005                                          
V25                          0.015  0.020 -0.003 -0.014  0.004                                   
V26                          0.032  0.007  0.004 -0.015 -0.006  0.006                            
V27                         -0.018 -0.020  0.003  0.003  0.001 -0.010 -0.003                     
V28                          0.068  0.000  0.001  0.000  0.002  0.003 -0.017  0.000              
V29                         -0.038  0.001 -0.012  0.002  0.017 -0.001 -0.018  0.001  0.000       
V30                          0.031  0.024 -0.007 -0.013 -0.011  0.013  0.061 -0.015  0.001 -0.014

Standardized residuals:
       Min         Q1        Med         Q3        Max 
-3.0866866 -0.5483974  0.1080253  0.6419830  2.6354891 

Residual standard error: 0.8999846 
Degrees of freedom: 235 total; 224 residual
          [,1]
[1,] 0.5013446
matx <- as.matrix(m$residuals); rownames(matx) <- rownames(mydata)
spac <- lets.correl(x=matx, y=distm, z=12, equidistant = T, plot = T)

moran.test(residuals(m), nb2listw(nb))$p.value # too much.
[1] 0.9215695
hist(resid(m))

plot(m, resid(., type = "p") ~ fitted(.), abline = 0)

plot(m, scale(I(vlog(cost))) ~ fitted(.), abline = c(0,1))

qqnorm(m)


for(i in c("V22", "V23", "V24", "V25", "V26", "V27", "V28", "V29", "V30")){
  x <- ggplot(world)+
  geom_sf() +
  geom_point(data = mydata[order(mydata[,i]),], aes(y=lat, x=lon, color = mydata[,i]), alpha = 0.9) +
  scale_color_viridis()+
  ggtitle(i)
  print(x)
}

Is thermal niche breadth predicted by latitude plus latitude2?


# vector 1 added ---
m <- gls(scale(I(vlog(tas_breadth))) ~ scale(lat) + scale(I(lat^2)) + V22 + V23 + V24 + V25 + V26 + V27 + V28 + V29 + V30 + V31 + V32 + V33 + V34 + V35 + V36 + V37, correlation = corPagel(0.99, phy = tree,fixed = F, form = ~Species.1), data = mydata, method = "REML"); summary(m); cor(predict(m),scale(I(vlog(mydata$cost))))
Generalized least squares fit by REML
  Model: scale(I(vlog(tas_breadth))) ~ scale(lat) + scale(I(lat^2)) +      V22 + V23 + V24 + V25 + V26 + V27 + V28 + V29 + V30 + V31 +      V32 + V33 + V34 + V35 + V36 + V37 
  Data: mydata 

Correlation Structure: corPagel
 Formula: ~Species.1 
 Parameter estimate(s):
   lambda 
0.5675592 

Coefficients:

 Correlation: 
                (Intr) scl(l) s(I(^2 V22    V23    V24    V25    V26    V27    V28    V29    V30    V31    V32    V33    V34    V35    V36   
scale(lat)       0.045                                                                                                                       
scale(I(lat^2)) -0.077  0.055                                                                                                                
V22              0.011 -0.056 -0.055                                                                                                         
V23              0.070  0.021  0.019  0.048                                                                                                  
V24              0.053  0.032 -0.058  0.076  0.005                                                                                           
V25             -0.024  0.005 -0.134  0.208  0.006  0.167                                                                                    
V26             -0.072 -0.037  0.034  0.040 -0.044 -0.007 -0.014                                                                             
V27             -0.007 -0.004 -0.078  0.050 -0.032 -0.022  0.090  0.028                                                                      
V28              0.028 -0.005 -0.006 -0.069 -0.003  0.037 -0.018 -0.057 -0.047                                                               
V29              0.002  0.011 -0.022 -0.006  0.002 -0.052  0.005  0.011  0.048 -0.004                                                        
V30             -0.038 -0.018 -0.018 -0.017 -0.009 -0.013 -0.005  0.030 -0.011 -0.008 -0.002                                                 
V31              0.005 -0.030 -0.009 -0.062 -0.030  0.021 -0.006 -0.046 -0.019  0.014 -0.023 -0.004                                          
V32              0.001 -0.005  0.012  0.022  0.004 -0.002 -0.021  0.004 -0.003 -0.002 -0.008 -0.011 -0.037                                   
V33             -0.008 -0.016 -0.070  0.043 -0.012 -0.014  0.026  0.012  0.050 -0.015  0.014  0.003 -0.007 -0.003                            
V34             -0.021  0.062  0.018 -0.018  0.010 -0.030 -0.030  0.026  0.022 -0.022  0.074  0.012 -0.027  0.010  0.036                     
V35             -0.005  0.012 -0.007 -0.006 -0.010 -0.013 -0.012 -0.001 -0.007 -0.001 -0.001  0.001 -0.020  0.002  0.003  0.004              
V36             -0.045 -0.014 -0.034  0.063 -0.007 -0.005  0.055  0.025  0.041 -0.022  0.021  0.008 -0.073 -0.028  0.013 -0.004 -0.003       
V37              0.027 -0.017 -0.021  0.004  0.017  0.013 -0.006  0.010 -0.006 -0.003 -0.015  0.002  0.008 -0.014 -0.005 -0.012  0.001 -0.008

Standardized residuals:
       Min         Q1        Med         Q3        Max 
-2.0731629 -0.6096382 -0.1790288  0.2623287  3.2865813 

Residual standard error: 0.5443762 
Degrees of freedom: 235 total; 216 residual
          [,1]
[1,] 0.1123255
matx <- as.matrix(m$residuals); rownames(matx) <- rownames(mydata)
spac <- lets.correl(x=matx, y=distm, z=12, equidistant = T, plot = T)

moran.test(residuals(m), nb2listw(nb))$p.value # too much.
[1] 0.9484634
hist(resid(m))

plot(m, resid(., type = "p") ~ fitted(.), abline = 0)

plot(m, scale(I(vlog(cost))) ~ fitted(.), abline = c(0,1))

qqnorm(m)


for(i in c("V22", "V23", "V24", "V25", "V26", "V27", "V28", "V29", "V30", "V31", "V32", "V33", "V34", "V35", "V36", "V37")){
  x <- ggplot(world)+
  geom_sf() +
  geom_point(data = mydata[order(mydata[,i]),], aes(y=lat, x=lon, color = mydata[,i]), alpha = 0.9) +
  scale_color_viridis()
  print(x)
}

Is cost predicted by latitude plus latitude2?


# vector 1 added ---
m <- gls(scale(I(vlog(cost))) ~ scale(lat) + scale(I(lat^2)) + V22 + V23 + V24 + V25, correlation = corPagel(0.99, phy = tree,fixed = F, form = ~Species.1), data = mydata, method = "REML"); summary(m); cor(predict(m),scale(I(vlog(mydata$cost))))
Generalized least squares fit by REML
  Model: scale(I(vlog(cost))) ~ scale(lat) + scale(I(lat^2)) + V22 + V23 +      V24 + V25 
  Data: mydata 

Correlation Structure: corPagel
 Formula: ~Species.1 
 Parameter estimate(s):
   lambda 
0.1048059 

Coefficients:

 Correlation: 
                (Intr) scl(l) s(I(^2 V22    V23    V24   
scale(lat)       0.001                                   
scale(I(lat^2)) -0.064  0.104                            
V22             -0.070 -0.017  0.013                     
V23             -0.041 -0.007 -0.006  0.011              
V24             -0.031  0.013  0.018  0.009  0.001       
V25              0.032  0.005 -0.013 -0.021 -0.008 -0.004

Standardized residuals:
       Min         Q1        Med         Q3        Max 
-3.2135868 -0.5833627  0.1685737  0.6876315  2.6281318 

Residual standard error: 0.9181122 
Degrees of freedom: 235 total; 228 residual
          [,1]
[1,] 0.4518531
matx <- as.matrix(m$residuals); rownames(matx) <- rownames(mydata)
spac <- lets.correl(x=matx, y=distm, z=12, equidistant = T, plot = T)

moran.test(residuals(m), nb2listw(nb))$p.value # too much.
[1] 0.7738208
hist(resid(m))

plot(m, resid(., type = "p") ~ fitted(.), abline = 0)

plot(m, scale(I(vlog(cost))) ~ fitted(.), abline = c(0,1))

qqnorm(m)


for(i in c("V22", "V23", "V24", "V25")){
  x <- ggplot(world)+
  geom_sf() +
  geom_point(data = mydata[order(mydata[,i]),], aes(y=lat, x=lon, color = mydata[,i]), alpha = 0.9) +
  scale_color_viridis()
  print(x)
}

Sensitivity Analyses

# 1 Pair age (all v. < 8mya (end of uplift of Andes))
# 2 Distance (all v. < 1500*1000) (1500 / 110 = ~ 22 degrees)
# 3 MAT_overlap (> 0% v. > 75% (more restrictive == more conservative for this measure.))
# 4 landgap (all v. nogap) *ALL GAPS ARE < 110km (two water grid cells marked as land for having >50% land @ 0.5 degree resolution.)
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKClByZXBhcmUgdGhlIFdvcmtzcGFjZQpgYGB7cn0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGVycm9yID0gRkFMU0UpICMgcm1kIG9wdGlvbnMKcm0obGlzdCA9IGxzKCkpOyBpbnZpc2libGUoZ2MoKSkgIyBjbGVhbmluZwpgYGAKPGJyPjxicj48YnI+PGJyPjxicj4KCkNvbnRyb2wgQmxvY2sKYGBge3J9IAojIGYsIGYsIDAuMjUgbG9va3MgbmljZS4KYWxsb3dtaWdyYW50cyA8LSBGICMgT1BUSU9OUzogVCwgRiAKYWxsb3dzeW1wYXRyeSA8LSBGICMgT1BUSU9OUzogVCwgRgptaW5vdmVycGVyYyA8LSAwICMgcmVtb3ZlIHBhaXJzIHRoYXQgZG8gbm90IGhhdmUgdGhlcm1hbCBvdmVybGFwIChhbmFnZW5lc2lzKQpjb3N0dmFyIDwtICJlbGUiCmBgYAo8YnI+PGJyPjxicj48YnI+PGJyPgoKUGFja2FnZXMgJiBQcmVmcwpgYGB7cn0Kb3B0aW9ucyhzY2lwZW4gPSA5OTkpICMgdHVybiBvZmYgc2NpZW50aWZpYyBub3RhdGlvbgonJW5vdGluJScgPC0gTmVnYXRlKCclaW4lJykKcmVxdWlyZShnZ3Bsb3QyKSAjIGxvYWQgcGFja2FnZXMKcmVxdWlyZShHR2FsbHkpCnJlcXVpcmUodmlyaWRpcykKcmVxdWlyZShjYXBlcikKbGlicmFyeShkcGx5cikKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KG1hcHMpCmxpYnJhcnkoYXBlKQpsaWJyYXJ5KEVudlN0YXRzKQpsaWJyYXJ5KGZvcmVjYXN0KQpyZXF1aXJlKG5sbWUpCnJlcXVpcmUoZ2VvZGlzdCkKcmVxdWlyZShsZXRzUikKcmVxdWlyZShzcGRlcCkKcmVxdWlyZShzcGF0aWFscmVnKQpyZXF1aXJlKHJuYXR1cmFsZWFydGgpCnJlcXVpcmUocm5hdHVyYWxlYXJ0aGRhdGEpCnJlcXVpcmUocmdlb3MpCnJlcXVpcmUoc2YpCnJlcXVpcmUocmdkYWwpCnJlcXVpcmUocmFzdGVyKQp3b3JsZCA8LSBuZV9jb2FzdGxpbmUoc2NhbGUgPSAibWVkaXVtIiwgcmV0dXJuY2xhc3MgPSAic2YiKQp2bG9nIDwtIGZ1bmN0aW9uKHgpewogICBsb2coIHggKyBhYnMobWluKCB4ICwgbmEucm0gPSBUKSkgKyAxKQp9CgpzZXR3ZCgifi9Cb3ggU3luYy9DQl9WRl9TaGFyZWQvRHJ5X0xhYi9Qcm9qZWN0cy9KTVBIL0FuYWx5emVfUHJvY2Vzc2VkX0NsdXN0ZXJfT3V0cHV0cy9EYXRhIikKZXhjbHVzaW9uIDwtIHJlYWQuY3N2KGZpbGUgPSAiZXhjbHVzaW9uX25vbnNpbXBhdHJpY19ub25taWdyYW50LmNzdiIpCmV4Y2x1c2lvbiRyZWFsbTFyZWRbaXMubmEoZXhjbHVzaW9uJHJlYWxtMXJlZCldIDwtICJOQSIgIyBOQSBpcyBub3J0aCBhbWVyaWNhIG5vdCBSJ3MgTkEgdmFsdWUuIGZpeC4KZXhjbHVzaW9uJHJlYWxtMmdyZWVuW2lzLm5hKGV4Y2x1c2lvbiRyZWFsbTJncmVlbildIDwtICJOQSIKYGBgCjxicj48YnI+PGJyPjxicj48YnI+CgpMb2FkIE1haW4gRGF0YQpgYGB7cn0KIyBtYWluIGRhdGFmcmFtZSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0Kc2V0d2QoIn4vQm94IFN5bmMvQ0JfVkZfU2hhcmVkL0RyeV9MYWIvUHJvamVjdHMvSk1QSC9Qcm9jZXNzX0NsdXN0ZXJfT3V0cHV0cy9EYXRhIikKbG9hZChmaWxlID0gICJQYWlyX0JhcnJpZXJfRGF0YV9GRUIyMDIxLnJkYXRhIikKbXlkYXRhIDwtIG15cGFpcmRhdGE7IHJtKG15cGFpcmRhdGEpCnJvd25hbWVzKG15ZGF0YSkgPC0gbXlkYXRhJFNwZWNpZXMuMQpteWRhdGFob2xkIDwtIG15ZGF0YQpgYGAKPGJyPjxicj48YnI+PGJyPjxicj4KCmluaXRpYWwgbWFza3MKYGBge3J9CiMgbWlncmF0aW9uIC0tLQppZihhbGxvd21pZ3JhbnRzID09IEYpewogIG15ZGF0YSA8LSBteWRhdGFbd2hpY2gobXlkYXRhJE1pZ3JhdGlvbiA9PSAxLjApLF0KfQoKIyBwYXRyeQppZihhbGxvd3N5bXBhdHJ5ID09IEYpewogIG15ZGF0YSA8LSBteWRhdGFbd2hpY2gobXlkYXRhWyxwYXN0ZTAoY29zdHZhciwgIl9jMCIpXSA+IDAgKSxdICMgZG9lc250IG1hdHRlciBpZiB5b3UgdXNlIGVsZSwgbWF0LCB2YXJ0IHBhdGhzIGhlcmUsIHdpbGwgYmUgc2FtZSBhbnN3ZXIKfQpgYGAKCnNvcnQKYGBge3J9Cm15ZGF0YSR1bmlxdWVQYWlySWQgPT0gZXhjbHVzaW9uJG15ZGF0YS51bmlxdWVQYWlySWQKeCA8LSBteWRhdGFbd2hpY2gobXlkYXRhJFNwZWNpZXMuMSA9PSAiQXB0ZXJ5eF9vd2VuaWkiKSxdCm15ZGF0YSA8LSBteWRhdGFbb3JkZXIobWF0Y2gobXlkYXRhJHVuaXF1ZVBhaXJJZCxleGNsdXNpb24kbXlkYXRhLnVuaXF1ZVBhaXJJZCkpLCBdCnkgPC0gbXlkYXRhW3doaWNoKG15ZGF0YSRTcGVjaWVzLjEgPT0gIkFwdGVyeXhfb3dlbmlpIiksXQojIHN1bSh5IT14LCBuYS5ybSA9IFQpICMgY2hlY2tzLgojIGhlYWQobXlkYXRhKQpteWRhdGEkdW5pcXVlUGFpcklkID09IGV4Y2x1c2lvbiRteWRhdGEudW5pcXVlUGFpcklkCnJtKHgseSkKYGBgCgoKCmBgYHtyfQojICMgQmFzaWMgcmFuZ2UgbWFwcyBmb3IgYWxsIHBhaXJzIChubyBwYXRocykKIyB3ZFBBTSA8LSAiL1VzZXJzL2JvdGVyb2xhYjEvQm94IFN5bmMvQ0JfVkZfU2hhcmVkL0RyeV9MYWIvUHJvamVjdHMvSk1QSC9QUkVQL1BBTS9EYXRhIgojIHNldHdkKHdkUEFNKTsgbG9hZCgiY2JQQU0ucmRhdGEiKQojIHNldHdkKCJ+L0JveCBTeW5jL0NCX1ZGX1NoYXJlZC9EcnlfTGFiL1Byb2plY3RzL0pNUEgvUHJvY2Vzc19DbHVzdGVyX091dHB1dHMvRGF0YSIpCiMgcGRmKCJwYWlybWFwczIucGRmIiwgd2lkdGggPSAxOSwgaGVpZ2h0ID0gOS4yNSkKIyBmb3IgKGkgaW4gMTpucm93KG15ZGF0YSkpewojIHggPC0gY2JQQU1bLGMoIkxvbmdpdHVkZSh4KSIsIkxhdGl0dWRlKHkpIixteWRhdGEkU3BlY2llcy4xYmxbaV0pXQojIHggPC0gYXMuZGF0YS5mcmFtZSh4W3hbLDNdID09IDEsXSkKIyBpZihuY29sKHgpID09IDEpIHsKIyAgIHggPC0gdCh4KQojICAgY29sbmFtZXMoeCkgPC0gYygibG9uIiwgImxhdCIsICJwcmVzIikKIyAgIHggPC0gYXMuZGF0YS5mcmFtZSh4KQojIH0gZWxzZSB7CiMgICBjb2xuYW1lcyh4KSA8LSBjKCJsb24iLCAibGF0IiwgInByZXMiKQojIH0KIyAKIyB5IDwtIGNiUEFNWyxjKCJMb25naXR1ZGUoeCkiLCJMYXRpdHVkZSh5KSIsbXlkYXRhJFNwZWNpZXMuMmJsW2ldKV0KIyB5IDwtIGFzLmRhdGEuZnJhbWUoeVt5WywzXSA9PSAxLF0pCiMgaWYobmNvbCh5KSA9PSAxKSB7CiMgICB5IDwtIHQoeSkKIyAgIGNvbG5hbWVzKHkpIDwtIGMoImxvbiIsICJsYXQiLCAicHJlcyIpCiMgICB5IDwtIGFzLmRhdGEuZnJhbWUoeSkKIyAKIyB9IGVsc2UgewojICAgY29sbmFtZXMoeSkgPC0gYygibG9uIiwgImxhdCIsICJwcmVzIikKIyB9CiMgeiA8LSBnZ3Bsb3Qod29ybGQpKwojICAgICBnZW9tX3NmKCkgKwojICAgICBnZW9tX3BvaW50KGRhdGEgPSB4LCBhZXMoeT1sYXQsIHg9bG9uKSwgY29sb3IgPSAicmVkIikgKwojICAgICBnZW9tX3BvaW50KGRhdGEgPSB5LCBhZXMoeT1sYXQsIHg9bG9uKSwgY29sb3IgPSAiZ3JlZW4iKSArCiMgICAgIHRoZW1lX2J3KCkgKwojICAgICBnZ3RpdGxlKGkpCiMgcHJpbnQoeikKIyB9CiMgcHJpbnQoaSkKIyBkZXYub2ZmKCkKYGBgCgpgYGB7cn0KbXlkYXRhX2V4Y2x1c2lvbiA8LSBjYmluZChteWRhdGEsIGV4Y2x1c2lvbikKc2F2ZShteWRhdGFfZXhjbHVzaW9uLCBmaWxlID0gIm15ZGF0YV9leGNsdXNpb24ucmRhdGEiKQpteWRhdGEkcmVhbG0xIDwtIGV4Y2x1c2lvbiRyZWFsbTFyZWQKbXlkYXRhJHJlYWxtMiA8LSBleGNsdXNpb24kcmVhbG0yZ3JlZW4KbXlkYXRhJHJlYWxtIDwtIHBhc3RlMChteWRhdGEkcmVhbG0xLCBteWRhdGEkcmVhbG0yKQp0YWJsZShteWRhdGEkcmVhbG0pCm15ZGF0YSRyZWFsbVtteWRhdGEkcmVhbG0gPT0gIkFBSU0iXTsgbXlkYXRhJHJlYWxtW215ZGF0YSRyZWFsbSA9PSAiSU1BQSJdIDwtICAiQUFJTSIKbXlkYXRhJHJlYWxtW215ZGF0YSRyZWFsbSA9PSAiQVRJTSJdOyBteWRhdGEkcmVhbG1bbXlkYXRhJHJlYWxtID09ICJJTUFUIl0gPC0gICJBVElNIgpteWRhdGEkcmVhbG1bbXlkYXRhJHJlYWxtID09ICJBVFBBIl07IG15ZGF0YSRyZWFsbVtteWRhdGEkcmVhbG0gPT0gIlBBQVQiXSA8LSAgIkFUUEEiCm15ZGF0YSRyZWFsbVtteWRhdGEkcmVhbG0gPT0gIklNTlQiXTsgbXlkYXRhJHJlYWxtW215ZGF0YSRyZWFsbSA9PSAiTlRJTSJdIDwtICAiSU1OVCIKbXlkYXRhJHJlYWxtW215ZGF0YSRyZWFsbSA9PSAiTlRBQSJdOyBteWRhdGEkcmVhbG1bbXlkYXRhJHJlYWxtID09ICJBQU5UIl0gPC0gICJOVEFBIgpteWRhdGEkcmVhbG1bbXlkYXRhJHJlYWxtID09ICJOVE5BIl07IG15ZGF0YSRyZWFsbVtteWRhdGEkcmVhbG0gPT0gIk5BTlQiXSA8LSAgIk5UTkEiCm15ZGF0YSRyZWFsbVtteWRhdGEkcmVhbG0gPT0gIlBBTkEiXTsgbXlkYXRhJHJlYWxtW215ZGF0YSRyZWFsbSA9PSAiTkFQQSJdIDwtICAiUEFOQSIKbXlkYXRhJHJlYWxtIDwtIGFzLmZhY3RvcihteWRhdGEkcmVhbG0pOyBteWRhdGEkcmVhbG0gPC0gcmVsZXZlbChteWRhdGEkcmVhbG0sICJOVE5UIikKCm15ZGF0YSRsYW5kZ2FwIDwtIGFzLmxvZ2ljYWwoZXhjbHVzaW9uJGlzbGFuZCkKCm15ZGF0YSRjb3Ntb3BvbGl0YW4gPC0gYXMubG9naWNhbChleGNsdXNpb24kY29zbW9wb2xpdGFuKQoKbXlkYXRhJG5ldy5vbGQgPC0gYXMubG9naWNhbChleGNsdXNpb24kbmV3Lm9sZCkKCnJtKGV4Y2x1c2lvbiwgbXlkYXRhX2V4Y2x1c2lvbikKYGBgCgoKCkltcG9zZSBtYXNrcyAmIGRvIGNhbGN1YXRpb25zCmBgYHtyfQojIGZpbHRlciBjb3Ntb3BvbGl0YW4gYW5kIG5ldy9vbGQgd29ybGQgc3BlY2llcyAodGhlcmUgYXJlIHJlbGF0aXZlbHkgZmV3IGFmdGVyIGltcG9zaW5nIHByZXZpb3VzIG1hc2tzLikKbXlkYXRhIDwtIG15ZGF0YVt3aGljaChteWRhdGEkY29zbW9wb2xpdGFuID09IEZBTFNFICYgbXlkYXRhJG5ldy5vbGQgPT0gRkFMU0UpLF0KCiMgZGVwZW5kZW50IHZhcmlhYmxlOiBlbGV2YXRpb25hbCBiYXJyaWVyIHNpemUgLS0tCm15ZGF0YSRjb3N0IDwtIG15ZGF0YVssIHBhc3RlMChjb3N0dmFyLCAiX2MyNSIpXSAKCiMgZGF0YSBmaWx0ZXJpbmcgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyAgdGhlcm1hbCBvdmVybGFwIC0tLQpteWRhdGEkTUFUX292ZXJsYXAgPC0gbXlkYXRhWyxwYXN0ZTAoIk1BVCIsICJfb3ZfcGVyY19zbXJuZ2UiKV0KbXlkYXRhIDwtIG15ZGF0YVtteWRhdGEkTUFUX292ZXJsYXAgPiBtaW5vdmVycGVyYyxdCgojIHVwZGF0ZSBzb3J0IG9yZGVyIC0tLS0tLS0tLS0tLS0tLS0tLS0tCm15ZGF0YSRzb3J0b3JkZXIgPC0gc2VxKDE6bnJvdyhteWRhdGEpKQoKIyBsb25naXR1ZGUgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpteWRhdGEkbG9uIDwtIG15ZGF0YVsscGFzdGUwKCJsb25fbWVhbl9wYWlyXyIsIGNvc3R2YXIsICJfYzI1IildCgojIGxhdGl0dWRlIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KbXlkYXRhJGxhdCA8LSBteWRhdGFbLHBhc3RlMCgibGF0X21lYW5fcGFpcl8iLCBjb3N0dmFyLCAiX2MyNSIpXQoKIyB0ZW1wZXJhdHVyZSBicmVhZHRoIC0tLS0tLS0tLS0tLS0tLS0tCm15ZGF0YSR0YXNfYnJlYWR0aCA8LSBteWRhdGEkdGFzX3JhbmdlICMgbWVhbihtZWFuKHNwMSBhbm51YWwgdGFzIHJhbmdlIC0tIG9uZSB2YWx1ZSBwZXIgY2VsbCksIG1lYW4oc3AyIGFubnVhbCB0YXMgcmFuZ2UgLS0gb25lIHZhbHVlIHBlciBjZWxsKSkKCiMgbWVhbiBhbm51YWwgdGVtcGVyYXR1cmUgLS0tLS0tLS0tLS0tLS0KbXlkYXRhJHRhc19wb3NpdGlvbiA8LSBteWRhdGEkdGFzX21lYW4gIyBtZWFuKG1lYW4oc3AxIGFubnVhbCB0YXMgbWVhbiAgLS0gb25lIHZhbHVlIHBlciBjZWxsKSwgbWVhbihzcDIgYW5udWFsIHRhcyBtZWFuICAtLSBvbmUgdmFsdWUgcGVyIGNlbGwpKQoKIyBwcmVjaXBpdGF0aW9uIGJyZWFkdGggLS0tLS0tLS0tLS0tLS0tIApteWRhdGEkcGNwX2JyZWFkdGggPC0gbXlkYXRhJHBjcF9yYW5nZSAjIG1lYW4obWVhbihzcDEgYW5udWFsIHBjcCByYW5nZSAgLS0gb25lIHZhbHVlIHBlciBjZWxsKSwgbWVhbihzcDIgYW5udWFsIHBjcCByYW5nZSAgLS0gb25lIHZhbHVlIHBlciBjZWxsKSkKCiMgcHJlY2lwaXRhdGlvbiBicmVhZHRoIC0tLS0tLS0tLS0tLS0tLSAKbXlkYXRhJHBjcF9wb3NpdGlvbiA8LSBteWRhdGEkcGNwX21lYW4gIyBtZWFuKG1lYW4oc3AxIGFubnVhbCBwY3AgbWVhbiAgLS0gb25lIHZhbHVlIHBlciBjZWxsKSwgbWVhbihzcDIgYW5udWFsIHBjcCBtZWFuICAtLSBvbmUgdmFsdWUgcGVyIGNlbGwpKQoKIyBkaXN0YW5jZSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpteWRhdGEkZGlzdGFuY2UgPC0gbXlkYXRhWyxwYXN0ZTAoImNlbnRyb2lkX2Rpc3RhbmNlXyIsY29zdHZhciwiX2MyNSIpXQoKIyBtb3VudGFpbiBtYXNzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQptdG5zIDwtIHJlYWRPR1IoZHNuPSJ+L0JveCBTeW5jL0NCX1ZGX1NoYXJlZC9EcnlfTGFiL1Byb2plY3RzL0pNUEgvT3RoZXJfSW5wdXRfRGF0YS9HTUJBIiwgbGF5ZXI9IkdNQkEgTW91bnRhaW4gSW52ZW50b3J5X3YxLjItV29ybGQiLCB2ZXJib3NlID0gRkFMU0UpCndkUEFNIDwtICIvVXNlcnMvYm90ZXJvbGFiMS9Cb3ggU3luYy9DQl9WRl9TaGFyZWQvRHJ5X0xhYi9Qcm9qZWN0cy9KTVBIL1BSRVAvUEFNL0RhdGEiCnNldHdkKHdkUEFNKTsgbG9hZCgiTG9uTGF0X0JpcmRQQU1fcmFzdGVyLnJkYXRhIikKbXRucyA8LSByYXN0ZXJpemUobXRucywgTG9uTGF0X0JpcmRQQU1fcmFzdGVyKQptdG5zQGRhdGFAdmFsdWVzWyFpcy5uYShtdG5zQGRhdGFAdmFsdWVzKV0gPC0gMSAjIHJlcGxhY2UgbW91bnRhaW4gSURzIHdpdGggc2ltcGxlIGNvZGluZy4gMSBmb3IgbW91bnRhaW4uLi4KbXRuc0BkYXRhQHZhbHVlc1tpcy5uYShtdG5zQGRhdGFAdmFsdWVzKV0gPC0gMCAjIC4uLjAgZm9yIG5vIG1vdW50YWluCgpteWRhdGEkbXRuX21hc3MgPC0gTkEKZm9yIChpIGluIDE6bnJvdyhteWRhdGEpKSB7CiAgY29vcmRzMTwtZGF0YS5mcmFtZShsb249bXlkYXRhJGxvbltpXSwgbGF0PW15ZGF0YSRsYXRbaV0pOyBjb29yZGluYXRlcyhjb29yZHMxKTwtYygibG9uIiwibGF0Iik7IGNycyhjb29yZHMxKTwtY3JzKExvbkxhdF9CaXJkUEFNX3Jhc3RlcikgIyBnZXQgY29vcmRpbmF0ZXMKICB6IDwtIGV4dHJhY3QobXRucywgY29vcmRzMSwgYnVmZmVyID0gcmFzdGVyOjpwb2ludERpc3RhbmNlKGMoMCwwKSwgYygwLDgpLCBsb25sYXQgPSBUKSkKICBteWRhdGEkbXRuX21hc3NbaV0gPC0gc3VtKHpbWzFdXSkgLyBsZW5ndGgoeltbMV1dKQp9CgpyYXN0ZXI6OnBvaW50RGlzdGFuY2UoYygwLDApLCBjKDAsOCksIGxvbmxhdCA9IFQpICMgY29ycmVzcG9uZHMgdG8gYSByYWRpdXMgb2YganVzdCBhYm91dCA4IGRlZ3JlZXMuCnJhc3Rlcjo6cG9pbnREaXN0YW5jZShjKDc1LDc1KSwgYyg3NSwoNzUrOCkpLCBsb25sYXQgPSBUKSAjIHBvbGFyIGNpcmNsZXMgYXJlIGJpZ2dlciwgYnV0IG5vdCB0aGF0IG11Y2ggYmlnZ2VyLiBzbyBzaG91bGQgYmUgT0suCnJhc3Rlcjo6cGxvdChtdG5zKQpyYXN0ZXI6OnBsb3Qod29ybGQkZ2VvbWV0cnksIGFkZCA9IFQpCnBsb3RyaXg6OmRyYXcuY2lyY2xlKDcwLCA0MCwgOCwgbnYgPSAxMDAwLCBib3JkZXIgPSAiaG90cGluayIsIGx0eSA9IDEsIGx3ZCA9IDEpCnBsb3RyaXg6OmRyYXcuY2lyY2xlKDE0MCwgLTUsIDgsIG52ID0gMTAwMCwgYm9yZGVyID0gImhvdHBpbmsiLCBsdHkgPSAxLCBsd2QgPSAxKQpwbG90cml4OjpkcmF3LmNpcmNsZSgtODAsIDEwLCA4LCBudiA9IDEwMDAsIGJvcmRlciA9ICJob3RwaW5rIiwgbHR5ID0gMSwgbHdkID0gMSkKcGxvdHJpeDo6ZHJhdy5jaXJjbGUoLTcwLCAtNTAsIDgsIG52ID0gMTAwMCwgYm9yZGVyID0gImhvdHBpbmsiLGx0eSA9IDEsIGx3ZCA9IDEpCgp4IDwtIGdncGxvdCh3b3JsZCkrCiAgZ2VvbV9zZigpICsKICBnZW9tX3BvaW50KGRhdGEgPSBteWRhdGFbb3JkZXIobXlkYXRhWywgIm10bl9tYXNzIl0sIGRlY3JlYXNpbmcgPSBGKSxdLCBhZXMoeT1sYXQsIHg9bG9uLCBjb2xvciA9IG10bl9tYXNzKSwgYWxwaGEgPSAwLjkpICsKICBnZ3RpdGxlKGkpK3NjYWxlX2NvbG9yX3ZpcmlkaXMoKQpwcmludCh4KQoKIyB3YXRlciBidWZmZXJpbmcgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQp3dHIgPC0gcmVhZF9zZigifi9Cb3ggU3luYy9DQl9WRl9TaGFyZWQvRHJ5X0xhYi9Qcm9qZWN0cy9KTVBIL090aGVyX0lucHV0X0RhdGEvbmVfNTBtX29jZWFuL25lXzUwbV9vY2Vhbi5zaHAiKQp0ZW1wIDwtIG10bnMKdmFsdWVzKHRlbXApIDwtIDEwMAp0ZW1wIDwtIG1hc2sodGVtcCwgd3RyKQp3dHIgPC0gbXRucwp2YWx1ZXMod3RyKSA8LSAwCnd0clt0ZW1wID09IDEwMF0gPC0gMTsgcm0odGVtcCkKcGxvdCh3dHIpCgpteWRhdGEkd3RyY2VsbHMgPC0gTkEKbXlkYXRhJHd0cm1hc3MgPC0gTkEKZm9yIChpIGluIDE6bnJvdyhteWRhdGEpKSB7CiAgY29vcmRzMTwtZGF0YS5mcmFtZShsb249bXlkYXRhJGxvbltpXSwgbGF0PW15ZGF0YSRsYXRbaV0pOyBjb29yZGluYXRlcyhjb29yZHMxKTwtYygibG9uIiwibGF0Iik7IGNycyhjb29yZHMxKTwtY3JzKExvbkxhdF9CaXJkUEFNX3Jhc3RlcikgIyBnZXQgY29vcmRpbmF0ZXMKICB6IDwtIGV4dHJhY3Qod3RyLCBjb29yZHMxLCBidWZmZXIgPSByYXN0ZXI6OnBvaW50RGlzdGFuY2UoYygwLDApLCBjKDAsOCksIGxvbmxhdCA9IFQpKQogIG15ZGF0YSRtaW5pcGxvdFtpXSA8LSBsZW5ndGgoeltbMV1dKQogIG15ZGF0YSR3dHJjZWxsc1tpXSA8LSBzdW0oeltbMV1dKQogIG15ZGF0YSR3dHJtYXNzW2ldIDwtIHN1bSh6W1sxXV0pIC8gbGVuZ3RoKHpbWzFdXSkKfQpteWRhdGEkd2F0ZXJfYnVmZmVyaW5nIDwtIG15ZGF0YSR3dHJtYXNzCgp4IDwtIGdncGxvdCh3b3JsZCkrCiAgZ2VvbV9zZigpICsKICBnZW9tX3BvaW50KGRhdGEgPSBteWRhdGFbb3JkZXIobXlkYXRhWywgIndhdGVyX2J1ZmZlcmluZyJdLCBkZWNyZWFzaW5nID0gRiksXSwgYWVzKHk9bGF0LCB4PWxvbiwgY29sb3IgPSB3YXRlcl9idWZmZXJpbmcpLCBhbHBoYSA9IDAuOSkgKwogIGdndGl0bGUoaSkrc2NhbGVfY29sb3JfdmlyaWRpcygpCnByaW50KHgpCgoKIyBkaXNwZXJzYWwgYWJpbGl0eSAtLS0tLS0tLS0tLS0tLS0tLS0tLQpkaXNwYWIgPC0gcmVhZC5jc3YoIn4vQm94IFN5bmMvQ0JfVkZfU2hhcmVkL0RyeV9MYWIvUHJvamVjdHMvSk1QSC9PdGhlcl9JbnB1dF9EYXRhL0JpcmQgSGFuZC1XaW5nIEluZGV4L0RhdGFzZXQgSFdJIDIwMjAtMDQtMTAuY3N2IikKbXlkYXRhJGRpc3BlcnNhbF9hYmlsaXR5IDwtIE5BCmZvciAoaSBpbiAxOm5yb3cobXlkYXRhKSl7CiAgZGlzcGFiX3NwMSA8LSBkaXNwYWIkSFdJW2Rpc3BhYiRJVUNOLm5hbWUgPT0gbXlkYXRhJFNwZWNpZXMuMWJsW2ldXQogIGRpc3BhYl9zcDIgPC0gZGlzcGFiJEhXSVtkaXNwYWIkSVVDTi5uYW1lID09IG15ZGF0YSRTcGVjaWVzLjJibFtpXV0KICBkaXNwYWJfcGFpciA8LSBtZWFuKGMoZGlzcGFiX3NwMSwgZGlzcGFiX3NwMiksIG5hLnJtID0gVCkKICBteWRhdGEkZGlzcGVyc2FsX2FiaWxpdHlbaV0gPC0gZGlzcGFiX3BhaXIKICBybShkaXNwYWJfc3AxLCBkaXNwYWJfc3AyLCBkaXNwYWJfcGFpcikKfQpteWRhdGEgPC0gbXlkYXRhWyFpcy5uYW4obXlkYXRhJGRpc3BlcnNhbF9hYmlsaXR5KSxdCgojIHBhaXIgYWdlIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCm15ZGF0YSRwYWlyX2FnZSA8LSBteWRhdGEkUGFpci5hZ2UuLk1ZLgoKIyBsZW5ndGggb2YgYm91bmRhcnkgLS0tLS0tLS0tLS0tLS0tLS0tLQpteWRhdGEkYm91bmRhcnlfbGVuZ3RoIDwtIG15ZGF0YSRib3VuZGFyeV9sZW5ndGhfZWxlX2MyNQoKIyByZXRhaW4gY29scyBvZiBpbnRlcmVzdCBvbmx5LgpteWRhdGEgPC0gbXlkYXRhWyxjKCJ1bmlxdWVQYWlySWQiLCAiU3BlY2llcy4xIiwgIlNwZWNpZXMuMiIsICJTcGVjaWVzLjFibCIsICJTcGVjaWVzLjJibCIsICJjb3N0IiwgImxhdCIsICJsb24iLAogICAgICAgICAgICAgICAgICAgICJ0YXNfYnJlYWR0aCIsInRhc19wb3NpdGlvbiIsICJwY3BfYnJlYWR0aCIsInBjcF9wb3NpdGlvbiIsICJtdG5fbWFzcyIsICJ3YXRlcl9idWZmZXJpbmciLCAKICAgICAgICAgICAgICAgICAgICAiZGlzcGVyc2FsX2FiaWxpdHkiLCAicGFpcl9hZ2UiLCAiZGlzdGFuY2UiLCAiYm91bmRhcnlfbGVuZ3RoIiwgIk1BVF9vdmVybGFwIiwgInJlYWxtIiwKICAgICAgICAgICAgICAgICAgICAibGFuZGdhcCIpXQpgYGAKCmxvYWQgcGh5bG8gYW5kIHBydW5lCmBgYHtyfQojIHBoeWxvIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpzZXR3ZCgifi9Cb3ggU3luYy9DQl9WRl9TaGFyZWQvRHJ5X0xhYi9Qcm9qZWN0cy9KTVBIL090aGVyX0lucHV0X0RhdGEvQmlyZFRyZWVzIikKbG9hZChmaWxlID0gIkJpcmRUcmVlcy5SZGF0YSIpCnRyZWUgPC0gdHJlZXNbWzFdXTsgcm0odHJlZXMpICMgcGljayB0cmVlIChWRiBHRVQgVFJFRVMgRlJPTSBDT09ORVkhISEgYW5kIHVzZSBNQ0MgdHJlZS4pIC0tIGN1cnJlbnRseSBqdXN0IHVzaW5nIHRyZWUgMSBoZXJlLiAKdHJlZSA8LSBkcm9wLnRpcCh0cmVlLCB0cmVlJHRpcC5sYWJlbFt3aGljaCh0cmVlJHRpcC5sYWJlbCAlbm90aW4lIG15ZGF0YSRTcGVjaWVzLjEpXSkgIyBpbml0aWFsIG5hbWUgbWF0Y2hpbmcuCm15ZGF0YSA8LSBteWRhdGFbd2hpY2gobXlkYXRhJFNwZWNpZXMuMSAlaW4lIHRyZWUkdGlwLmxhYmVsKSxdCm15ZGF0YSA8LSBteWRhdGFbbWF0Y2godHJlZSR0aXAubGFiZWwsIG15ZGF0YSRTcGVjaWVzLjEpLF0Kc3VtKG15ZGF0YSRTcGVjaWVzLjEgIT0gdHJlZSR0aXAubGFiZWwpICMgc29ydGVkIChidXQgc3RpbGwgc3BlY2lmeSBmb3JtIGJlbG93IGZvciBzYWZldHkpCmBgYAoKU2F2ZSBmcmVhbWUgZm9yIENCCmBgYHtyfQpzZXR3ZCgifi9Cb3ggU3luYy9DQl9WRl9TaGFyZWQvRHJ5X0xhYi9Qcm9qZWN0cy9KTVBIL0FuYWx5emVfUHJvY2Vzc2VkX0NsdXN0ZXJfT3V0cHV0cy9EYXRhIikKc2F2ZShteWRhdGEsIGZpbGUgPSAiZWxlX2RhdGFfZm9yX0NCLnJkYXRhIikKd3JpdGUuY3N2KG15ZGF0YSwgZmlsZSA9ICJlbGVfZGF0YV9mb3JfQ0IuY3N2IikKYGBgCgoKCk5laWdoYm9ycyBmb3Igc3B0aWFsIGFuYWx5c2lzLiAKYGBge3J9CmRpc3RtIDwtIG15ZGF0YVssYygibG9uIiwgImxhdCIpXQpkaXN0bSA8LSBnZW9kaXN0KGRpc3RtLCBtZWFzdXJlID0gImdlb2Rlc2ljIikKcm93bmFtZXMoZGlzdG0pIDwtIHJvd25hbWVzKG15ZGF0YSkKY29sbmFtZXMoZGlzdG0pIDwtIHJvd25hbWVzKG15ZGF0YSkKYmFzZWNvbHMgPC0gbmNvbChteWRhdGEpCgojIG5laWdodGJvcnMKY29vcmRzPC1jYmluZChteWRhdGEkbG9uLCBteWRhdGEkbGF0KTsgY29vcmRzPC1hcy5tYXRyaXgoY29vcmRzKSA7IHJvdy5uYW1lcyhjb29yZHMpPC1yb3duYW1lcyhteWRhdGEpCmsxIDwtIGtubjJuYihrbmVhcm5laWdoKGNvb3JkcywgbG9uZ2xhdCA9IFQpKQpuYjwtIGRuZWFybmVpZ2goY29vcmRzLHJvdy5uYW1lcyA9IHJvdy5uYW1lcyhjb29yZHMpLCBkMT0wLGQyPW1heCh1bmxpc3QobmJkaXN0cyhrMSwgY29vcmRzLCBsb25nbGF0ID0gVCkpKSxsb25nbGF0PVQpCmBgYAoKCnBsb3RzIGZvciB0cmFuc2Zvcm1hdGlvbnMKYGBge3J9CmZvciAoaSBpbiBjKCJjb3N0IiwgImxhdCIsICJsb24iLCJ0YXNfYnJlYWR0aCIsInRhc19wb3NpdGlvbiIsInBjcF9icmVhZHRoIiwicGNwX3Bvc2l0aW9uIiwgIm10bl9tYXNzIiwgImRpc3BlcnNhbF9hYmlsaXR5IiwgInBhaXJfYWdlIiwgImRpc3RhbmNlIiwgImJvdW5kYXJ5X2xlbmd0aCIsICJNQVRfb3ZlcmxhcCIpKSB7Cmhpc3QobXlkYXRhWywgaV0sIGJyZWFrcyA9IDUwLCBtYWluID0gaSkKfQpgYGAKCndvcmxkIHBsb3RzCmBgYHtyfQpzZXR3ZCgifi9Cb3ggU3luYy9DQl9WRl9TaGFyZWQvRHJ5X0xhYi9Qcm9qZWN0cy9KTVBIL0FuYWx5emVfUHJvY2Vzc2VkX0NsdXN0ZXJfT3V0cHV0cy9EYXRhIikKIyBwZGYoZmlsZT0idmFyaWFibGVfbWFwcy5wZGYiLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA3KQpmb3IgKGkgaW4gYygiY29zdCIsICJsYXQiLCAibG9uIiwidGFzX2JyZWFkdGgiLCJ0YXNfcG9zaXRpb24iLCJwY3BfYnJlYWR0aCIsInBjcF9wb3NpdGlvbiIsICJtdG5fbWFzcyIsICAid2F0ZXJfYnVmZmVyaW5nIiwgImRpc3BlcnNhbF9hYmlsaXR5IiwgInBhaXJfYWdlIiwgImRpc3RhbmNlIiwgImJvdW5kYXJ5X2xlbmd0aCIsICJNQVRfb3ZlcmxhcCIsICJyZWFsbSIsICJsYW5kZ2FwIikpIHsKICBpZihpICVpbiUgYygiY29zdCIpKXsKICAgIG15YyA8LSBteWRhdGFbLCBpXTsgbXljIDwtIHZsb2cobXljKQogICAgeCA8LSBnZ3Bsb3Qod29ybGQpKwogICAgICBnZW9tX3NmKCkgKwogICAgICBnZW9tX3BvaW50KGRhdGEgPSBteWRhdGFbb3JkZXIobXlkYXRhWywgaV0sIGRlY3JlYXNpbmcgPSBGKSxdLCBhZXMoeT1sYXQsIHg9bG9uLCBjb2xvciA9IG15YyksIGFscGhhID0gMC44NSkgKwogICAgICBnZ3RpdGxlKHBhc3RlMCgibG4gIixpKSkrCiAgICAgIHNjYWxlX2NvbG9yX3ZpcmlkaXMoKQogICAgcHJpbnQoeCkKICB9IGVsc2UgaWYgKGkgJWluJSBjKCJyZWFsbSIsICJsYW5kZ2FwIikpewogICAgeCA8LSBnZ3Bsb3Qod29ybGQpKwogICAgICBnZW9tX3NmKCkgKyAKICAgICAgZ2VvbV9wb2ludChkYXRhID0gbXlkYXRhW29yZGVyKG15ZGF0YVssICJjb3N0Il0sIGRlY3JlYXNpbmcgPSBGKSxdLCBhZXMoeT1sYXQsIHg9bG9uLCBjb2xvciA9IGdldChpKSksIGFscGhhID0gMC44NSkgKwogICAgICBnZ3RpdGxlKHBhc3RlMChpKSkrCiAgICAgIHNjYWxlX2NvbG9yX3ZpcmlkaXMoZGlzY3JldGUgPSBUKQogICAgcHJpbnQoeCkgCiAgfSBlbHNlIHsKICAgIHggPC0gZ2dwbG90KHdvcmxkKSsKICAgICAgZ2VvbV9zZigpICsgCiAgICAgIGdlb21fcG9pbnQoZGF0YSA9IG15ZGF0YVtvcmRlcihteWRhdGFbLCAiY29zdCJdLCBkZWNyZWFzaW5nID0gRiksXSwgYWVzKHk9bGF0LCB4PWxvbiwgY29sb3IgPSBnZXQoaSkpLCBhbHBoYSA9IDAuODUpICsKICAgICAgZ2d0aXRsZShpKSsKICAgICAgc2NhbGVfY29sb3JfdmlyaWRpcygpCiAgICBwcmludCh4KSAKICB9Cn0KIyBkZXYub2ZmKCkKYGBgCgoKYGBge3J9Cm15ZGF0YSA8LSBteWRhdGFbLCAxOmJhc2Vjb2xzXQojIG5vIHNwYXRpYWwgZmlsdGVyaW5nIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQptIDwtIGdscyhzY2FsZShJKHZsb2coY29zdCkpKSB+IHNjYWxlKEkodmxvZyh0YXNfYnJlYWR0aCkpKSwgY29ycmVsYXRpb24gPSBjb3JQYWdlbCgwLjk5LCBwaHkgPSB0cmVlLCBmaXhlZCA9IEYsIGZvcm0gPSB+U3BlY2llcy4xKSwgZGF0YSA9IG15ZGF0YSwgbWV0aG9kID0gIlJFTUwiKTtzdW1tYXJ5KG0pCnByaW50KHBhc3RlKCJDb3JyZWxhdGlvbiBiZXR3ZWVuIGRhdGEgYW5kIHByZWRpY3Rpb246ICAiLCBjb3IocHJlZGljdChtKSxzY2FsZShJKHZsb2cobXlkYXRhJGNvc3QpKSkpKSkKaGlzdChyZXNpZChtKSkKcGxvdChtLCByZXNpZCguLCB0eXBlID0gInAiKSB+IGZpdHRlZCguKSwgYWJsaW5lID0gMCkKcGxvdChtLCBzY2FsZShJKHZsb2coY29zdCkpKSB+IGZpdHRlZCguKSwgYWJsaW5lID0gYygwLDEpKQpxcW5vcm0obSkKCiMgcGxvdCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KcGxvdChzY2FsZShJKHZsb2cobXlkYXRhJHRhc19icmVhZHRoKSkpLCBzY2FsZShJKHZsb2cobXlkYXRhJGNvc3QpKSksIHBjaCA9IDE2LAogICAgIHhsYWIgPSAidGhlcm1hbCBuaWNoZSBicmVhZHRoIiwgeWxhYiA9IHBhc3RlMCgibG9nICIsIGNvc3R2YXIsICIgY29zdCIgKSwgbWFpbiA9ICJHbG9iYWwgbW9kZWwiKQpteXggPC0gc2VxKG1pbihzY2FsZSh2bG9nKG15ZGF0YSR0YXNfYnJlYWR0aCkpKSwgbWF4KHNjYWxlKHZsb2cobXlkYXRhJHRhc19icmVhZHRoKSkpLCBsZW5ndGgub3V0PTEwMCkgIyBwbG90IGZpdApteWNvZWZzPC1jb2VmKG0pCm15eSA8LSBteWNvZWZzWzFdICsgbXljb2Vmc1syXSpteXgKbGluZXMoYygwLDApLCBjKC0xMCwxMDApLCBsdHk9MikKbGluZXMobXl4LG15eSxjb2wgPSAncmVkJykKbSA8LSBnbHMoc2NhbGUoSSh2bG9nKGNvc3QpKSkgfiBzY2FsZShJKGxvZyh0YXNfYnJlYWR0aCkpKSwgZGF0YSA9IG15ZGF0YSwgbWV0aG9kID0gIlJFTUwiKQpteXggPC0gc2VxKG1pbihzY2FsZSh2bG9nKG15ZGF0YSR0YXNfYnJlYWR0aCkpKSwgbWF4KHNjYWxlKHZsb2cobXlkYXRhJHRhc19icmVhZHRoKSkpLCBsZW5ndGgub3V0PTEwMCkgIyBwbG90IGZpdApteWNvZWZzPC1jb2VmKG0pCm15eSA8LSBteWNvZWZzWzFdICsgbXljb2Vmc1syXSpteXgKbGluZXMoYygwLDApLCBjKC0xMCwxMDApLCBsdHk9MikKbGluZXMobXl4LG15eSxjb2wgPSAncmVkJywgbHR5PTIpCgoKCgojIHdpdGggc3BhdGlhbCBmaWx0ZXJpbmcgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQptIDwtIGdscyhzY2FsZShJKHZsb2coY29zdCkpKSB+IHNjYWxlKEkodmxvZyh0YXNfYnJlYWR0aCkpKSwgY29ycmVsYXRpb24gPSBjb3JQYWdlbCgwLjk5LCBwaHkgPSB0cmVlLCBmaXhlZCA9IEYsIGZvcm0gPSB+U3BlY2llcy4xKSwgZGF0YSA9IG15ZGF0YSwgbWV0aG9kID0gIlJFTUwiKQojIHNwYXRpYWwgYXV0b2NvcnIgLS0tLS0tLS0tLS0tLS0tLS0tLS0tCm1hdHggPC0gYXMubWF0cml4KG0kcmVzaWR1YWxzKTsgcm93bmFtZXMobWF0eCkgPC0gcm93bmFtZXMobXlkYXRhKQpzcGFjIDwtIGxldHMuY29ycmVsKHg9bWF0eCwgeT1kaXN0bSwgej0xMiwgZXF1aWRpc3RhbnQgPSBULCBwbG90ID0gVCkKbW9yYW4udGVzdChyZXNpZHVhbHMobSksIG5iMmxpc3R3KG5iKSkkcC52YWx1ZSAjIG5vIGV2aWRlbmNlIG9mIHNwYXRpYWwgY29tcG9uZW50Li4gCgojIHNwYXRpYWwgZmlsdGVyaW5nIC0tLS0tLS0tLS0tLS0tLS0tLS0tCnJtKHNhcmNvbCkKc2FyY29sIDwtIFNwYXRpYWxGaWx0ZXJpbmcoZm9ybXVsYSA9IHNjYWxlKEkodmxvZyhjb3N0KSkpIH4gc2NhbGUoSSh2bG9nKHRhc19icmVhZHRoKSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gbXlkYXRhLG5iPW5iLCBzdHlsZT0iVyIsIEV4YWN0RVYgPSBUUlVFKQpteWRhdGFbLGMoKGJhc2Vjb2xzKzEpOihiYXNlY29scysxKyBkaW0oZml0dGVkKHNhcmNvbCkpWzJdLTEpKV08LWZpdHRlZChzYXJjb2wpCmNvbG5hbWVzKG15ZGF0YSkKCiMgdmVjdG9yIDEgYWRkZWQgLS0tCm0gPC0gZ2xzKHNjYWxlKEkodmxvZyhjb3N0KSkpIH4gc2NhbGUoSSh2bG9nKHRhc19icmVhZHRoKSkpICsgVjIyICsgVjIzICsgVjI0ICsgVjI1ICsgVjI2ICsgVjI3ICsgVjI4ICsgVjI5ICsgVjMwLCBjb3JyZWxhdGlvbiA9IGNvclBhZ2VsKDAuOTksIHBoeSA9IHRyZWUsZml4ZWQgPSBGLCBmb3JtID0gflNwZWNpZXMuMSksIGRhdGEgPSBteWRhdGEsIG1ldGhvZCA9ICJSRU1MIik7IHN1bW1hcnkobSk7IGNvcihwcmVkaWN0KG0pLHNjYWxlKEkodmxvZyhteWRhdGEkY29zdCkpKSkKbWF0eCA8LSBhcy5tYXRyaXgobSRyZXNpZHVhbHMpOyByb3duYW1lcyhtYXR4KSA8LSByb3duYW1lcyhteWRhdGEpCnNwYWMgPC0gbGV0cy5jb3JyZWwoeD1tYXR4LCB5PWRpc3RtLCB6PTEyLCBlcXVpZGlzdGFudCA9IFQsIHBsb3QgPSBUKQptb3Jhbi50ZXN0KHJlc2lkdWFscyhtKSwgbmIybGlzdHcobmIpKSRwLnZhbHVlICMgdG9vIG11Y2guCmhpc3QocmVzaWQobSkpCnBsb3QobSwgcmVzaWQoLiwgdHlwZSA9ICJwIikgfiBmaXR0ZWQoLiksIGFibGluZSA9IDApCnBsb3QobSwgc2NhbGUoSSh2bG9nKGNvc3QpKSkgfiBmaXR0ZWQoLiksIGFibGluZSA9IGMoMCwxKSkKcXFub3JtKG0pCgpmb3IoaSBpbiBjKCJWMjIiLCAiVjIzIiwgIlYyNCIsICJWMjUiLCAiVjI2IiwgIlYyNyIsICJWMjgiLCAiVjI5IiwgIlYzMCIpKXsKICB4IDwtIGdncGxvdCh3b3JsZCkrCiAgZ2VvbV9zZigpICsKICBnZW9tX3BvaW50KGRhdGEgPSBteWRhdGFbb3JkZXIobXlkYXRhWyxpXSksXSwgYWVzKHk9bGF0LCB4PWxvbiwgY29sb3IgPSBteWRhdGFbLGldKSwgYWxwaGEgPSAwLjkpICsKICBzY2FsZV9jb2xvcl92aXJpZGlzKCkrCiAgZ2d0aXRsZShpKQogIHByaW50KHgpCn0KYGBgCgoKSXMgdGhlcm1hbCBuaWNoZSBicmVhZHRoIHByZWRpY3RlZCBieSBsYXRpdHVkZSBwbHVzIGxhdGl0dWRlMj8gCmBgYHtyfQpteWRhdGEgPC0gbXlkYXRhWywgMTpiYXNlY29sc10KbSA8LSBnbHMoc2NhbGUoSSh2bG9nKHRhc19icmVhZHRoKSkpIH4gc2NhbGUobGF0KSArIHNjYWxlKEkobGF0XjIpKSwgY29ycmVsYXRpb24gPSBjb3JQYWdlbCgwLjk5LCBwaHkgPSB0cmVlLCBmaXhlZCA9IEYsIGZvcm0gPSB+U3BlY2llcy4xKSwgZGF0YSA9IG15ZGF0YSwgbWV0aG9kID0gIlJFTUwiKTsgc3VtbWFyeShtKQpwcmludChwYXN0ZSgiQ29ycmVsYXRpb24gYmV0d2VlbiBkYXRhIGFuZCBwcmVkaWN0aW9uOiAgIiwgY29yKHByZWRpY3QobSksc2NhbGUoSSh2bG9nKG15ZGF0YSR0YXNfYnJlYWR0aCkpKSkpKQpoaXN0KHJlc2lkKG0pKQpwbG90KG0sIHJlc2lkKC4sIHR5cGUgPSAicCIpIH4gZml0dGVkKC4pLCBhYmxpbmUgPSAwKQpwbG90KG0sIHNjYWxlKEkodmxvZyhjb3N0KSkpIH4gZml0dGVkKC4pLCBhYmxpbmUgPSBjKDAsMSkpCnFxbm9ybShtKQoKIyBwbG90IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpwbG90KHNjYWxlKG15ZGF0YSRsYXQpLCBzY2FsZShJKHZsb2cobXlkYXRhJHRhc19icmVhZHRoKSkpLCBwY2ggPSAxNiwKICAgICB4bGFiID0gImxhdGl0dWRlIiwgeWxhYiA9ICJ0aGVybWFsIG5pY2hlIGJyZWFkdGgiLCBtYWluID0gIkdsb2JhbCBtb2RlbCIpCm15eCA8LSBzZXEobWluKHNjYWxlKG15ZGF0YSRsYXQpKSwgbWF4KHNjYWxlKG15ZGF0YSRsYXQpKSwgbGVuZ3RoLm91dD0xMDApICMgcGxvdCBmaXQKbXljb2VmczwtY29lZihtKQpteXkgPC0gbXljb2Vmc1sxXSArIG15Y29lZnNbMl0qbXl4ICsgbXljb2Vmc1szXSpteXheMgpsaW5lcyhjKDAsMCksIGMoLTEwLDEwMCksIGx0eT0yKQpsaW5lcyhteXgsbXl5LGNvbCA9ICdyZWQnKQptIDwtIGdscyhzY2FsZShJKHZsb2codGFzX2JyZWFkdGgpKSkgfiBzY2FsZShsYXQpICsgc2NhbGUoSShsYXReMikpLCBkYXRhID0gbXlkYXRhLCBtZXRob2QgPSAiUkVNTCIpCm15eCA8LSBzZXEobWluKHNjYWxlKG15ZGF0YSRsYXQpKSwgbWF4KHNjYWxlKG15ZGF0YSRsYXQpKSwgbGVuZ3RoLm91dD0xMDApICMgcGxvdCBmaXQKbXljb2VmczwtY29lZihtKQpteXkgPC0gbXljb2Vmc1sxXSArIG15Y29lZnNbMl0qbXl4ICsgbXljb2Vmc1szXSpteXheMgpsaW5lcyhjKDAsMCksIGMoLTEwLDEwMCksIGx0eT0yKQpsaW5lcyhteXgsbXl5LGNvbCA9ICdyZWQnLCBsdHk9MikKCgoKCgoKIyB3aXRoIHNwYXRpYWwgZmlsdGVyaW5nIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KbSA8LSBnbHMoc2NhbGUoSSh2bG9nKHRhc19icmVhZHRoKSkpIH4gc2NhbGUobGF0KSArIHNjYWxlKEkobGF0XjIpKSwgY29ycmVsYXRpb24gPSBjb3JQYWdlbCgwLjk5LCBwaHkgPSB0cmVlLCBmaXhlZCA9IEYsIGZvcm0gPSB+U3BlY2llcy4xKSwgZGF0YSA9IG15ZGF0YSwgbWV0aG9kID0gIlJFTUwiKQojIHNwYXRpYWwgYXV0b2NvcnIgLS0tLS0tLS0tLS0tLS0tLS0tLS0tCm1hdHggPC0gYXMubWF0cml4KG0kcmVzaWR1YWxzKTsgcm93bmFtZXMobWF0eCkgPC0gcm93bmFtZXMobXlkYXRhKQpzcGFjIDwtIGxldHMuY29ycmVsKHg9bWF0eCwgeT1kaXN0bSwgej0xMiwgZXF1aWRpc3RhbnQgPSBULCBwbG90ID0gVCkKbW9yYW4udGVzdChyZXNpZHVhbHMobSksIG5iMmxpc3R3KG5iKSkkcC52YWx1ZSAjIG5vIGV2aWRlbmNlIG9mIHNwYXRpYWwgY29tcG9uZW50Li4gCgojIHNwYXRpYWwgZmlsdGVyaW5nIC0tLS0tLS0tLS0tLS0tLS0tLS0tCnJtKHNhcmNvbCkKc2FyY29sIDwtIFNwYXRpYWxGaWx0ZXJpbmcoZm9ybXVsYSA9IHNjYWxlKEkodmxvZyh0YXNfYnJlYWR0aCkpKSB+IHNjYWxlKGxhdCkgKyBzY2FsZShJKGxhdF4yKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBteWRhdGEsbmI9bmIsIHN0eWxlPSJXIiwgRXhhY3RFViA9IFRSVUUpCm15ZGF0YVssYygoYmFzZWNvbHMrMSk6KGJhc2Vjb2xzKzErIGRpbShmaXR0ZWQoc2FyY29sKSlbMl0tMSkpXTwtZml0dGVkKHNhcmNvbCkKY29sbmFtZXMobXlkYXRhKSAKCiMgdmVjdG9yIDEgYWRkZWQgLS0tCm0gPC0gZ2xzKHNjYWxlKEkodmxvZyh0YXNfYnJlYWR0aCkpKSB+IHNjYWxlKGxhdCkgKyBzY2FsZShJKGxhdF4yKSkgKyBWMjIgKyBWMjMgKyBWMjQgKyBWMjUgKyBWMjYgKyBWMjcgKyBWMjggKyBWMjkgKyBWMzAgKyBWMzEgKyBWMzIgKyBWMzMgKyBWMzQgKyBWMzUgKyBWMzYgKyBWMzcsIGNvcnJlbGF0aW9uID0gY29yUGFnZWwoMC45OSwgcGh5ID0gdHJlZSxmaXhlZCA9IEYsIGZvcm0gPSB+U3BlY2llcy4xKSwgZGF0YSA9IG15ZGF0YSwgbWV0aG9kID0gIlJFTUwiKTsgc3VtbWFyeShtKTsgY29yKHByZWRpY3QobSksc2NhbGUoSSh2bG9nKG15ZGF0YSRjb3N0KSkpKQptYXR4IDwtIGFzLm1hdHJpeChtJHJlc2lkdWFscyk7IHJvd25hbWVzKG1hdHgpIDwtIHJvd25hbWVzKG15ZGF0YSkKc3BhYyA8LSBsZXRzLmNvcnJlbCh4PW1hdHgsIHk9ZGlzdG0sIHo9MTIsIGVxdWlkaXN0YW50ID0gVCwgcGxvdCA9IFQpCm1vcmFuLnRlc3QocmVzaWR1YWxzKG0pLCBuYjJsaXN0dyhuYikpJHAudmFsdWUgIyB0b28gbXVjaC4KaGlzdChyZXNpZChtKSkKcGxvdChtLCByZXNpZCguLCB0eXBlID0gInAiKSB+IGZpdHRlZCguKSwgYWJsaW5lID0gMCkKcGxvdChtLCBzY2FsZShJKHZsb2coY29zdCkpKSB+IGZpdHRlZCguKSwgYWJsaW5lID0gYygwLDEpKQpxcW5vcm0obSkKCmZvcihpIGluIGMoIlYyMiIsICJWMjMiLCAiVjI0IiwgIlYyNSIsICJWMjYiLCAiVjI3IiwgIlYyOCIsICJWMjkiLCAiVjMwIiwgIlYzMSIsICJWMzIiLCAiVjMzIiwgIlYzNCIsICJWMzUiLCAiVjM2IiwgIlYzNyIpKXsKICB4IDwtIGdncGxvdCh3b3JsZCkrCiAgZ2VvbV9zZigpICsKICBnZW9tX3BvaW50KGRhdGEgPSBteWRhdGFbb3JkZXIobXlkYXRhWyxpXSksXSwgYWVzKHk9bGF0LCB4PWxvbiwgY29sb3IgPSBteWRhdGFbLGldKSwgYWxwaGEgPSAwLjkpICsKICBzY2FsZV9jb2xvcl92aXJpZGlzKCkKICBwcmludCh4KQp9CmBgYAoKSXMgY29zdCAgcHJlZGljdGVkIGJ5IGxhdGl0dWRlIHBsdXMgbGF0aXR1ZGUyPyAKYGBge3J9Cm15ZGF0YSA8LSBteWRhdGFbLCAxOmJhc2Vjb2xzXQptIDwtIGdscyhzY2FsZShJKHZsb2coY29zdCkpKSB+IHNjYWxlKGxhdCkgKyBzY2FsZShJKGxhdF4yKSksIGNvcnJlbGF0aW9uID0gY29yUGFnZWwoMC45OSwgcGh5ID0gdHJlZSwgZml4ZWQgPSBGLCBmb3JtID0gflNwZWNpZXMuMSksIGRhdGEgPSBteWRhdGEsIG1ldGhvZCA9ICJSRU1MIik7IHN1bW1hcnkobSkKcHJpbnQocGFzdGUoIkNvcnJlbGF0aW9uIGJldHdlZW4gZGF0YSBhbmQgcHJlZGljdGlvbjogICIsIGNvcihwcmVkaWN0KG0pLHNjYWxlKEkodmxvZyhteWRhdGEkY29zdCkpKSkpKQpoaXN0KHJlc2lkKG0pKQpwbG90KG0sIHJlc2lkKC4sIHR5cGUgPSAicCIpIH4gZml0dGVkKC4pLCBhYmxpbmUgPSAwKQpwbG90KG0sIHNjYWxlKEkodmxvZyhjb3N0KSkpIH4gZml0dGVkKC4pLCBhYmxpbmUgPSBjKDAsMSkpCnFxbm9ybShtKQoKIyBwbG90IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpwbG90KHNjYWxlKG15ZGF0YSRsYXQpLCBzY2FsZShJKHZsb2cobXlkYXRhJGNvc3QpKSksIHBjaCA9IDE2LAogICAgIHhsYWIgPSAibGF0aXR1ZGUiLCB5bGFiID0gImNvc3QiLCBtYWluID0gIkdsb2JhbCBtb2RlbCIpCm15eCA8LSBzZXEobWluKHNjYWxlKG15ZGF0YSRsYXQpKSwgbWF4KHNjYWxlKG15ZGF0YSRsYXQpKSwgbGVuZ3RoLm91dD0xMDApICMgcGxvdCBmaXQKbXljb2VmczwtY29lZihtKQpteXkgPC0gbXljb2Vmc1sxXSArIG15Y29lZnNbMl0qbXl4ICsgbXljb2Vmc1szXSpteXheMgpsaW5lcyhjKDAsMCksIGMoLTEwLDEwMCksIGx0eT0yKQpsaW5lcyhteXgsbXl5LGNvbCA9ICdyZWQnKQptIDwtIGdscyhzY2FsZShJKHZsb2coY29zdCkpKSB+IHNjYWxlKGxhdCkgKyBzY2FsZShJKGxhdF4yKSksIGRhdGEgPSBteWRhdGEsIG1ldGhvZCA9ICJSRU1MIikKbXl4IDwtIHNlcShtaW4oc2NhbGUobXlkYXRhJGxhdCkpLCBtYXgoc2NhbGUobXlkYXRhJGxhdCkpLCBsZW5ndGgub3V0PTEwMCkgIyBwbG90IGZpdApteWNvZWZzPC1jb2VmKG0pCm15eSA8LSBteWNvZWZzWzFdICsgbXljb2Vmc1syXSpteXggKyBteWNvZWZzWzNdKm15eF4yCmxpbmVzKGMoMCwwKSwgYygtMTAsMTAwKSwgbHR5PTIpCmxpbmVzKG15eCxteXksY29sID0gJ3JlZCcsIGx0eT0yKQoKCgoKCgojIHdpdGggc3BhdGlhbCBmaWx0ZXJpbmcgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQptIDwtIGdscyhzY2FsZShJKHZsb2coY29zdCkpKSB+IHNjYWxlKGxhdCkgKyBzY2FsZShJKGxhdF4yKSksIGNvcnJlbGF0aW9uID0gY29yUGFnZWwoMC45OSwgcGh5ID0gdHJlZSwgZml4ZWQgPSBGLCBmb3JtID0gflNwZWNpZXMuMSksIGRhdGEgPSBteWRhdGEsIG1ldGhvZCA9ICJSRU1MIikKIyBzcGF0aWFsIGF1dG9jb3JyIC0tLS0tLS0tLS0tLS0tLS0tLS0tLQptYXR4IDwtIGFzLm1hdHJpeChtJHJlc2lkdWFscyk7IHJvd25hbWVzKG1hdHgpIDwtIHJvd25hbWVzKG15ZGF0YSkKc3BhYyA8LSBsZXRzLmNvcnJlbCh4PW1hdHgsIHk9ZGlzdG0sIHo9MTIsIGVxdWlkaXN0YW50ID0gVCwgcGxvdCA9IFQpCm1vcmFuLnRlc3QocmVzaWR1YWxzKG0pLCBuYjJsaXN0dyhuYikpJHAudmFsdWUgIyBubyBldmlkZW5jZSBvZiBzcGF0aWFsIGNvbXBvbmVudC4uIAoKIyBzcGF0aWFsIGZpbHRlcmluZyAtLS0tLS0tLS0tLS0tLS0tLS0tLQpybShzYXJjb2wpCnNhcmNvbCA8LSBTcGF0aWFsRmlsdGVyaW5nKGZvcm11bGEgPSBzY2FsZShJKHZsb2coY29zdCkpKSB+IHNjYWxlKGxhdCkgKyBzY2FsZShJKGxhdF4yKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBteWRhdGEsbmI9bmIsIHN0eWxlPSJXIiwgRXhhY3RFViA9IFRSVUUpCm15ZGF0YVssYygoYmFzZWNvbHMrMSk6KGJhc2Vjb2xzKzErIGRpbShmaXR0ZWQoc2FyY29sKSlbMl0tMSkpXTwtZml0dGVkKHNhcmNvbCkKY29sbmFtZXMobXlkYXRhKSAKCiMgdmVjdG9yIDEgYWRkZWQgLS0tCm0gPC0gZ2xzKHNjYWxlKEkodmxvZyhjb3N0KSkpIH4gc2NhbGUobGF0KSArIHNjYWxlKEkobGF0XjIpKSArIFYyMiArIFYyMyArIFYyNCArIFYyNSwgY29ycmVsYXRpb24gPSBjb3JQYWdlbCgwLjk5LCBwaHkgPSB0cmVlLGZpeGVkID0gRiwgZm9ybSA9IH5TcGVjaWVzLjEpLCBkYXRhID0gbXlkYXRhLCBtZXRob2QgPSAiUkVNTCIpOyBzdW1tYXJ5KG0pOyBjb3IocHJlZGljdChtKSxzY2FsZShJKHZsb2cobXlkYXRhJGNvc3QpKSkpCm1hdHggPC0gYXMubWF0cml4KG0kcmVzaWR1YWxzKTsgcm93bmFtZXMobWF0eCkgPC0gcm93bmFtZXMobXlkYXRhKQpzcGFjIDwtIGxldHMuY29ycmVsKHg9bWF0eCwgeT1kaXN0bSwgej0xMiwgZXF1aWRpc3RhbnQgPSBULCBwbG90ID0gVCkKbW9yYW4udGVzdChyZXNpZHVhbHMobSksIG5iMmxpc3R3KG5iKSkkcC52YWx1ZSAjIHRvbyBtdWNoLgpoaXN0KHJlc2lkKG0pKQpwbG90KG0sIHJlc2lkKC4sIHR5cGUgPSAicCIpIH4gZml0dGVkKC4pLCBhYmxpbmUgPSAwKQpwbG90KG0sIHNjYWxlKEkodmxvZyhjb3N0KSkpIH4gZml0dGVkKC4pLCBhYmxpbmUgPSBjKDAsMSkpCnFxbm9ybShtKQoKZm9yKGkgaW4gYygiVjIyIiwgIlYyMyIsICJWMjQiLCAiVjI1IikpewogIHggPC0gZ2dwbG90KHdvcmxkKSsKICBnZW9tX3NmKCkgKwogIGdlb21fcG9pbnQoZGF0YSA9IG15ZGF0YVtvcmRlcihteWRhdGFbLGldKSxdLCBhZXMoeT1sYXQsIHg9bG9uLCBjb2xvciA9IG15ZGF0YVssaV0pLCBhbHBoYSA9IDAuOSkgKwogIHNjYWxlX2NvbG9yX3ZpcmlkaXMoKQogIHByaW50KHgpCn0KYGBgCgoKYGBge3J9Cm15ZGF0YSA8LSBteWRhdGFbLCAxOmJhc2Vjb2xzXQptIDwtIGdscyhzY2FsZShJKHZsb2coY29zdCkpKSB+IHNjYWxlKEkoKHRhc19icmVhZHRoKSkpICsgc2NhbGUoSSgodGFzX3Bvc2l0aW9uKSkpICsgc2NhbGUoSSgocGNwX2JyZWFkdGgpKSkgKyBzY2FsZShJKChwY3BfcG9zaXRpb24pKSkgKyAKICAgICAgICAgICBzY2FsZShJKChtdG5fbWFzcykpKSArIHNjYWxlKEkoKHdhdGVyX2J1ZmZlcmluZykpKSArIHNjYWxlKEkoKGRpc3BlcnNhbF9hYmlsaXR5KSkpICsgc2NhbGUoSSgocGFpcl9hZ2UpKSkgKyBzY2FsZShJKChkaXN0YW5jZSkpKSArIHNjYWxlKEkoKGJvdW5kYXJ5X2xlbmd0aCkpKSArIAogICAgICAgICAgIHNjYWxlKEkoKE1BVF9vdmVybGFwKSkpICsgbGFuZGdhcCArIHJlYWxtLAogICAgICAgICBjb3JyZWxhdGlvbiA9IGNvclBhZ2VsKDAuOTksIHBoeSA9IHRyZWUsIGZpeGVkID0gRiwgZm9ybSA9IH5TcGVjaWVzLjEpLCBkYXRhID0gbXlkYXRhLCBtZXRob2QgPSAiUkVNTCIpO3N1bW1hcnkobSkKIyBjYXI6OnZpZihtKSAjIGRvZXMgbm90IHdvcmsgd2l0aCByZWFsbSBhZGRlZCBpbi4gCnByaW50KHBhc3RlKCJDb3JyZWxhdGlvbiBiZXR3ZWVuIGRhdGEgYW5kIHByZWRpY3Rpb246ICAiLCBjb3IocHJlZGljdChtKSxzY2FsZShJKHZsb2cobXlkYXRhJGNvc3QpKSkpKSkKaGlzdChyZXNpZChtKSkKcGxvdChtLCByZXNpZCguLCB0eXBlID0gInAiKSB+IGZpdHRlZCguKSwgYWJsaW5lID0gMCkKcGxvdChtLCBzY2FsZShJKHZsb2coY29zdCkpKSB+IGZpdHRlZCguKSwgYWJsaW5lID0gYygwLDEpKQpxcW5vcm0obSkKCgojIHNwYXRpYWwgYXV0b2NvcnIgLS0tLS0tLS0tLS0tLS0tLS0tLS0tCm1hdHggPC0gYXMubWF0cml4KG0kcmVzaWR1YWxzKTsgcm93bmFtZXMobWF0eCkgPC0gcm93bmFtZXMobXlkYXRhKQpzcGFjIDwtIGxldHMuY29ycmVsKHg9bWF0eCwgeT1kaXN0bSwgej0xMiwgZXF1aWRpc3RhbnQgPSBULCBwbG90ID0gVCkKbW9yYW4udGVzdChyZXNpZHVhbHMobSksIG5iMmxpc3R3KG5iKSkkcC52YWx1ZSAjIG5vIGV2aWRlbmNlIG9mIHNwYXRpYWwgY29tcG9uZW50Li4gCgojIHNwYXRpYWwgZmlsdGVyaW5nIC0tLS0tLS0tLS0tLS0tLS0tLS0tCnJtKHNhcmNvbCkKc2FyY29sIDwtIFNwYXRpYWxGaWx0ZXJpbmcoc2NhbGUoSSh2bG9nKGNvc3QpKSkgfiBzY2FsZShJKCh0YXNfYnJlYWR0aCkpKSArIHNjYWxlKEkoKHRhc19wb3NpdGlvbikpKSArIHNjYWxlKEkoKHBjcF9icmVhZHRoKSkpICsgc2NhbGUoSSgocGNwX3Bvc2l0aW9uKSkpICsgCiAgICAgICAgICAgc2NhbGUoSSgobXRuX21hc3MpKSkgKyBzY2FsZShJKCh3YXRlcl9idWZmZXJpbmcpKSkgKyBzY2FsZShJKChkaXNwZXJzYWxfYWJpbGl0eSkpKSArIHNjYWxlKEkoKHBhaXJfYWdlKSkpICsgc2NhbGUoSSgoZGlzdGFuY2UpKSkgKyBzY2FsZShJKChib3VuZGFyeV9sZW5ndGgpKSkgKyAKICAgICAgICAgICBzY2FsZShJKChNQVRfb3ZlcmxhcCkpKSArIGxhbmRnYXAgKyByZWFsbSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IG15ZGF0YSxuYj1uYiwgc3R5bGU9IlciLCBFeGFjdEVWID0gVFJVRSkKbXlkYXRhWyxjKChiYXNlY29scysxKTooYmFzZWNvbHMrMSsgZGltKGZpdHRlZChzYXJjb2wpKVsyXS0xKSldPC1maXR0ZWQoc2FyY29sKQpjb2xuYW1lcyhteWRhdGEpIAoKIyB2ZWN0b3IgMSBhZGRlZCAtLS0KbXlkYXRhJHJlYWxtMiA8LSBhcy5mYWN0b3IobXlkYXRhJHJlYWxtMik7IG15ZGF0YSRyZWFsbTIgPC0gcmVsZXZlbChteWRhdGEkcmVhbG0yLCByZWYgPSAiTlQiKQptIDwtIGdscyhzY2FsZShJKHZsb2coY29zdCkpKSB+IHNjYWxlKEkoKHRhc19icmVhZHRoKSkpICsgc2NhbGUoSSgodGFzX3Bvc2l0aW9uKSkpICsgc2NhbGUoSSgocGNwX2JyZWFkdGgpKSkgKyBzY2FsZShJKChwY3BfcG9zaXRpb24pKSkgKyAKICAgICAgICAgICBzY2FsZShJKChtdG5fbWFzcykpKSArIHNjYWxlKEkoKHdhdGVyX2J1ZmZlcmluZykpKSArIHNjYWxlKEkoKGRpc3BlcnNhbF9hYmlsaXR5KSkpICsgc2NhbGUoSSgocGFpcl9hZ2UpKSkgKyBzY2FsZShJKChkaXN0YW5jZSkpKSArIHNjYWxlKEkoKGJvdW5kYXJ5X2xlbmd0aCkpKSArIAogICAgICAgICAgIHNjYWxlKEkoKE1BVF9vdmVybGFwKSkpICsgbGFuZGdhcCArIHJlYWxtICsgVjIyICsgVjIzICsgVjI0ICsgVjI1ICsgVjI2ICsgVjI3ICsgVjI4ICsgVjI5ICsgVjMwICsgVjMxICsgVjMyICsgVjMzLCBjb3JyZWxhdGlvbiA9IGNvclBhZ2VsKDAuOTksIHBoeSA9IHRyZWUsIGZpeGVkID0gRiwgZm9ybSA9IH5TcGVjaWVzLjEpLCBkYXRhID0gbXlkYXRhLCBtZXRob2QgPSAiUkVNTCIpOyBzdW1tYXJ5KG0pOyBjb3IocHJlZGljdChtKSxzY2FsZShJKHZsb2cobXlkYXRhJGNvc3QpKSkpCm1hdHggPC0gYXMubWF0cml4KG0kcmVzaWR1YWxzKTsgcm93bmFtZXMobWF0eCkgPC0gcm93bmFtZXMobXlkYXRhKQpzcGFjIDwtIGxldHMuY29ycmVsKHg9bWF0eCwgeT1kaXN0bSwgej0xMiwgZXF1aWRpc3RhbnQgPSBULCBwbG90ID0gVCkKbW9yYW4udGVzdChyZXNpZHVhbHMobSksIG5iMmxpc3R3KG5iKSkkcC52YWx1ZSAjIHRvbyBtdWNoLgpoaXN0KHJlc2lkKG0pKQpwbG90KG0sIHJlc2lkKC4sIHR5cGUgPSAicCIpIH4gZml0dGVkKC4pLCBhYmxpbmUgPSAwKQpwbG90KG0sIHNjYWxlKEkodmxvZyhjb3N0KSkpIH4gZml0dGVkKC4pLCBhYmxpbmUgPSBjKDAsMSkpCnFxbm9ybShtKQoKCmZvcihpIGluIGMoIlYyMiIsIlYyMyIsICJWMjQiLCAiVjI1IiwgIlYyNiIsICJWMjciLCAiVjI4IiwgIlYyOSIsICJWMzAiLCAiVjMxIiwgIlYzMiIsICJWMzMiKSl7CiAgeCA8LSBnZ3Bsb3Qod29ybGQpKwogIGdlb21fc2YoKSArCiAgZ2VvbV9wb2ludChkYXRhID0gbXlkYXRhW29yZGVyKG15ZGF0YVssaV0pLF0sIGFlcyh5PWxhdCwgeD1sb24sIGNvbG9yID0gbXlkYXRhWyxpXSksIGFscGhhID0gMC45KSArCiAgc2NhbGVfY29sb3JfdmlyaWRpcygpCiAgcHJpbnQoeCkKfQpgYGAKCgpTZW5zaXRpdml0eSBBbmFseXNlcwpgYGB7cn0KIyAxIFBhaXIgYWdlIChhbGwgdi4gPCA4bXlhIChlbmQgb2YgdXBsaWZ0IG9mIEFuZGVzKSkKIyAyIERpc3RhbmNlIChhbGwgdi4gPCAxNTAwKjEwMDApICgxNTAwIC8gMTEwID0gfiAyMiBkZWdyZWVzKQojIDMgTUFUX292ZXJsYXAgKD4gMCUgdi4gPiA3NSUgKG1vcmUgcmVzdHJpY3RpdmUgPT0gbW9yZSBjb25zZXJ2YXRpdmUgZm9yIHRoaXMgbWVhc3VyZS4pKQojIDQgbGFuZGdhcCAoYWxsIHYuIG5vZ2FwKSAqQUxMIEdBUFMgQVJFIDwgMTEwa20gKHR3byB3YXRlciBncmlkIGNlbGxzIG1hcmtlZCBhcyBsYW5kIGZvciBoYXZpbmcgPjUwJSBsYW5kIEAgMC41IGRlZ3JlZSByZXNvbHV0aW9uLikKYGBg